1 /*
2 * Copyright (c) 2011-2012, 2014-2015 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief UART-driven console
10 *
11 *
12 * Serial console driver.
13 * Hooks into the printk and fputc (for printf) modules. Poll driven.
14 */
15
16 #include <zephyr/kernel.h>
17
18 #include <stdio.h>
19 #include <zephyr/types.h>
20 #include <zephyr/sys/__assert.h>
21 #include <errno.h>
22 #include <ctype.h>
23
24 #include <zephyr/device.h>
25 #include <zephyr/init.h>
26
27 #include <zephyr/drivers/uart.h>
28 #include <zephyr/drivers/console/console.h>
29 #include <zephyr/drivers/console/uart_console.h>
30 #include <zephyr/toolchain.h>
31 #include <zephyr/linker/sections.h>
32 #include <zephyr/sys/atomic.h>
33 #include <zephyr/sys/printk.h>
34 #include <zephyr/pm/device_runtime.h>
35 #ifdef CONFIG_UART_CONSOLE_MCUMGR
36 #include <zephyr/mgmt/mcumgr/transport/serial.h>
37 #endif
38
39 static const struct device *const uart_console_dev =
40 DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
41
42 #ifdef CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS
43
44 static uart_console_in_debug_hook_t debug_hook_in;
uart_console_in_debug_hook_install(uart_console_in_debug_hook_t hook)45 void uart_console_in_debug_hook_install(uart_console_in_debug_hook_t hook)
46 {
47 debug_hook_in = hook;
48 }
49
UART_CONSOLE_OUT_DEBUG_HOOK_SIG(debug_hook_out_nop)50 static UART_CONSOLE_OUT_DEBUG_HOOK_SIG(debug_hook_out_nop) {
51 ARG_UNUSED(c);
52 return !UART_CONSOLE_DEBUG_HOOK_HANDLED;
53 }
54
55 static uart_console_out_debug_hook_t *debug_hook_out = debug_hook_out_nop;
uart_console_out_debug_hook_install(uart_console_out_debug_hook_t * hook)56 void uart_console_out_debug_hook_install(uart_console_out_debug_hook_t *hook)
57 {
58 debug_hook_out = hook;
59 }
60 #define HANDLE_DEBUG_HOOK_OUT(c) \
61 (debug_hook_out(c) == UART_CONSOLE_DEBUG_HOOK_HANDLED)
62
63 #endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */
64
65
66 #if defined(CONFIG_PRINTK) || defined(CONFIG_STDOUT_CONSOLE)
67 /**
68 *
69 * @brief Output one character to UART
70 *
71 * Outputs both line feed and carriage return in the case of a '\n'.
72 *
73 * @param c Character to output
74 *
75 * @return The character passed as input.
76 */
77
console_out(int c)78 static int console_out(int c)
79 {
80 #ifdef CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS
81
82 int handled_by_debug_server = HANDLE_DEBUG_HOOK_OUT(c);
83
84 if (handled_by_debug_server) {
85 return c;
86 }
87
88 #endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */
89
90 if (pm_device_runtime_is_enabled(uart_console_dev)) {
91 if (pm_device_runtime_get(uart_console_dev) < 0) {
92 /* Enabling the UART instance has failed but this
93 * function MUST return the byte output.
94 */
95 return c;
96 }
97 }
98
99 if ('\n' == c) {
100 uart_poll_out(uart_console_dev, '\r');
101 }
102 uart_poll_out(uart_console_dev, c);
103
104 if (pm_device_runtime_is_enabled(uart_console_dev)) {
105 /* As errors cannot be returned, ignore the return value */
106 (void)pm_device_runtime_put(uart_console_dev);
107 }
108
109 return c;
110 }
111
112 #endif
113
114 #if defined(CONFIG_STDOUT_CONSOLE)
115 extern void __stdout_hook_install(int (*hook)(int c));
116 #endif
117
118 #if defined(CONFIG_PRINTK)
119 extern void __printk_hook_install(int (*fn)(int c));
120 #endif
121
122 #if defined(CONFIG_CONSOLE_HANDLER)
123 static struct k_fifo *avail_queue;
124 static struct k_fifo *lines_queue;
125 static uint8_t (*completion_cb)(char *line, uint8_t len);
126
127 /* Control characters */
128 #define BS 0x08
129 #define ESC 0x1b
130 #define DEL 0x7f
131
132 /* ANSI escape sequences */
133 #define ANSI_ESC '['
134 #define ANSI_UP 'A'
135 #define ANSI_DOWN 'B'
136 #define ANSI_FORWARD 'C'
137 #define ANSI_BACKWARD 'D'
138 #define ANSI_END 'F'
139 #define ANSI_HOME 'H'
140 #define ANSI_DEL '~'
141
read_uart(const struct device * uart,uint8_t * buf,unsigned int size)142 static int read_uart(const struct device *uart, uint8_t *buf,
143 unsigned int size)
144 {
145 int rx;
146
147 rx = uart_fifo_read(uart, buf, size);
148 if (rx < 0) {
149 /* Overrun issue. Stop the UART */
150 uart_irq_rx_disable(uart);
151
152 return -EIO;
153 }
154
155 return rx;
156 }
157
cursor_forward(unsigned int count)158 static inline void cursor_forward(unsigned int count)
159 {
160 printk("\x1b[%uC", count);
161 }
162
cursor_backward(unsigned int count)163 static inline void cursor_backward(unsigned int count)
164 {
165 printk("\x1b[%uD", count);
166 }
167
cursor_save(void)168 static inline void cursor_save(void)
169 {
170 printk("\x1b[s");
171 }
172
cursor_restore(void)173 static inline void cursor_restore(void)
174 {
175 printk("\x1b[u");
176 }
177
insert_char(char * pos,char c,uint8_t end)178 static void insert_char(char *pos, char c, uint8_t end)
179 {
180 char tmp;
181
182 /* Echo back to console */
183 uart_poll_out(uart_console_dev, c);
184
185 if (end == 0U) {
186 *pos = c;
187 return;
188 }
189
190 tmp = *pos;
191 *(pos++) = c;
192
193 cursor_save();
194
195 while (end-- > 0) {
196 uart_poll_out(uart_console_dev, tmp);
197 c = *pos;
198 *(pos++) = tmp;
199 tmp = c;
200 }
201
202 /* Move cursor back to right place */
203 cursor_restore();
204 }
205
del_char(char * pos,uint8_t end)206 static void del_char(char *pos, uint8_t end)
207 {
208 uart_poll_out(uart_console_dev, '\b');
209
210 if (end == 0U) {
211 uart_poll_out(uart_console_dev, ' ');
212 uart_poll_out(uart_console_dev, '\b');
213 return;
214 }
215
216 cursor_save();
217
218 while (end-- > 0) {
219 *pos = *(pos + 1);
220 uart_poll_out(uart_console_dev, *(pos++));
221 }
222
223 uart_poll_out(uart_console_dev, ' ');
224
225 /* Move cursor back to right place */
226 cursor_restore();
227 }
228
229 enum {
230 ESC_ESC,
231 ESC_ANSI,
232 ESC_ANSI_FIRST,
233 ESC_ANSI_VAL,
234 ESC_ANSI_VAL_2,
235 #ifdef CONFIG_UART_CONSOLE_MCUMGR
236 ESC_MCUMGR_PKT_1,
237 ESC_MCUMGR_PKT_2,
238 ESC_MCUMGR_FRAG_1,
239 ESC_MCUMGR_FRAG_2,
240 #endif
241 };
242
243 static atomic_t esc_state;
244 static unsigned int ansi_val, ansi_val_2;
245 static uint8_t cur, end;
246
handle_ansi(uint8_t byte,char * line)247 static void handle_ansi(uint8_t byte, char *line)
248 {
249 if (atomic_test_and_clear_bit(&esc_state, ESC_ANSI_FIRST)) {
250 if (isdigit(byte) == 0) {
251 ansi_val = 1U;
252 goto ansi_cmd;
253 }
254
255 atomic_set_bit(&esc_state, ESC_ANSI_VAL);
256 ansi_val = byte - '0';
257 ansi_val_2 = 0U;
258 return;
259 }
260
261 if (atomic_test_bit(&esc_state, ESC_ANSI_VAL)) {
262 if (isdigit(byte) != 0) {
263 if (atomic_test_bit(&esc_state, ESC_ANSI_VAL_2)) {
264 ansi_val_2 *= 10U;
265 ansi_val_2 += byte - '0';
266 } else {
267 ansi_val *= 10U;
268 ansi_val += byte - '0';
269 }
270 return;
271 }
272
273 /* Multi value sequence, e.g. Esc[Line;ColumnH */
274 if (byte == ';' &&
275 !atomic_test_and_set_bit(&esc_state, ESC_ANSI_VAL_2)) {
276 return;
277 }
278
279 atomic_clear_bit(&esc_state, ESC_ANSI_VAL);
280 atomic_clear_bit(&esc_state, ESC_ANSI_VAL_2);
281 }
282
283 ansi_cmd:
284 switch (byte) {
285 case ANSI_BACKWARD:
286 if (ansi_val > cur) {
287 break;
288 }
289
290 end += ansi_val;
291 cur -= ansi_val;
292 cursor_backward(ansi_val);
293 break;
294 case ANSI_FORWARD:
295 if (ansi_val > end) {
296 break;
297 }
298
299 end -= ansi_val;
300 cur += ansi_val;
301 cursor_forward(ansi_val);
302 break;
303 case ANSI_HOME:
304 if (!cur) {
305 break;
306 }
307
308 cursor_backward(cur);
309 end += cur;
310 cur = 0U;
311 break;
312 case ANSI_END:
313 if (!end) {
314 break;
315 }
316
317 cursor_forward(end);
318 cur += end;
319 end = 0U;
320 break;
321 case ANSI_DEL:
322 if (!end) {
323 break;
324 }
325
326 cursor_forward(1);
327 del_char(&line[cur], --end);
328 break;
329 default:
330 break;
331 }
332
333 atomic_clear_bit(&esc_state, ESC_ANSI);
334 }
335
336 #ifdef CONFIG_UART_CONSOLE_MCUMGR
337
clear_mcumgr(void)338 static void clear_mcumgr(void)
339 {
340 atomic_clear_bit(&esc_state, ESC_MCUMGR_PKT_1);
341 atomic_clear_bit(&esc_state, ESC_MCUMGR_PKT_2);
342 atomic_clear_bit(&esc_state, ESC_MCUMGR_FRAG_1);
343 atomic_clear_bit(&esc_state, ESC_MCUMGR_FRAG_2);
344 }
345
346 /**
347 * These states indicate whether an mcumgr frame is being received.
348 */
349 #define CONSOLE_MCUMGR_STATE_NONE 1
350 #define CONSOLE_MCUMGR_STATE_HEADER 2
351 #define CONSOLE_MCUMGR_STATE_PAYLOAD 3
352
read_mcumgr_byte(uint8_t byte)353 static int read_mcumgr_byte(uint8_t byte)
354 {
355 bool frag_1;
356 bool frag_2;
357 bool pkt_1;
358 bool pkt_2;
359
360 pkt_1 = atomic_test_bit(&esc_state, ESC_MCUMGR_PKT_1);
361 pkt_2 = atomic_test_bit(&esc_state, ESC_MCUMGR_PKT_2);
362 frag_1 = atomic_test_bit(&esc_state, ESC_MCUMGR_FRAG_1);
363 frag_2 = atomic_test_bit(&esc_state, ESC_MCUMGR_FRAG_2);
364
365 if (pkt_2 || frag_2) {
366 /* Already fully framed. */
367 return CONSOLE_MCUMGR_STATE_PAYLOAD;
368 }
369
370 if (pkt_1) {
371 if (byte == MCUMGR_SERIAL_HDR_PKT_2) {
372 /* Final framing byte received. */
373 atomic_set_bit(&esc_state, ESC_MCUMGR_PKT_2);
374 return CONSOLE_MCUMGR_STATE_PAYLOAD;
375 }
376 } else if (frag_1) {
377 if (byte == MCUMGR_SERIAL_HDR_FRAG_2) {
378 /* Final framing byte received. */
379 atomic_set_bit(&esc_state, ESC_MCUMGR_FRAG_2);
380 return CONSOLE_MCUMGR_STATE_PAYLOAD;
381 }
382 } else {
383 if (byte == MCUMGR_SERIAL_HDR_PKT_1) {
384 /* First framing byte received. */
385 atomic_set_bit(&esc_state, ESC_MCUMGR_PKT_1);
386 return CONSOLE_MCUMGR_STATE_HEADER;
387 } else if (byte == MCUMGR_SERIAL_HDR_FRAG_1) {
388 /* First framing byte received. */
389 atomic_set_bit(&esc_state, ESC_MCUMGR_FRAG_1);
390 return CONSOLE_MCUMGR_STATE_HEADER;
391 }
392 }
393
394 /* Non-mcumgr byte received. */
395 return CONSOLE_MCUMGR_STATE_NONE;
396 }
397
398 /**
399 * @brief Attempts to process a received byte as part of an mcumgr frame.
400 *
401 * @param cmd The console command currently being received.
402 * @param byte The byte just received.
403 *
404 * @return true if the command being received is an mcumgr frame; false if it
405 * is a plain console command.
406 */
handle_mcumgr(struct console_input * cmd,uint8_t byte)407 static bool handle_mcumgr(struct console_input *cmd, uint8_t byte)
408 {
409 int mcumgr_state;
410
411 mcumgr_state = read_mcumgr_byte(byte);
412 if (mcumgr_state == CONSOLE_MCUMGR_STATE_NONE) {
413 /* Not an mcumgr command; let the normal console handling
414 * process the byte.
415 */
416 cmd->is_mcumgr = 0;
417 return false;
418 }
419
420 /* The received byte is part of an mcumgr command. Process the byte
421 * and return true to indicate that normal console handling should
422 * ignore it.
423 */
424 if (cur + end < sizeof(cmd->line) - 1) {
425 cmd->line[cur++] = byte;
426 }
427 if (mcumgr_state == CONSOLE_MCUMGR_STATE_PAYLOAD && byte == '\n') {
428 cmd->line[cur + end] = '\0';
429 cmd->is_mcumgr = 1;
430 k_fifo_put(lines_queue, cmd);
431
432 clear_mcumgr();
433 cmd = NULL;
434 cur = 0U;
435 end = 0U;
436 }
437
438 return true;
439 }
440
441 #endif /* CONFIG_UART_CONSOLE_MCUMGR */
442
uart_console_isr(const struct device * unused,void * user_data)443 static void uart_console_isr(const struct device *unused, void *user_data)
444 {
445 ARG_UNUSED(unused);
446 ARG_UNUSED(user_data);
447 static uint8_t last_char = '\0';
448
449 while (uart_irq_update(uart_console_dev) &&
450 uart_irq_is_pending(uart_console_dev)) {
451 static struct console_input *cmd;
452 uint8_t byte;
453 int rx;
454
455 if (!uart_irq_rx_ready(uart_console_dev)) {
456 continue;
457 }
458
459 /* Character(s) have been received */
460
461 rx = read_uart(uart_console_dev, &byte, 1);
462 if (rx < 0) {
463 return;
464 }
465
466 #ifdef CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS
467 if (debug_hook_in != NULL && debug_hook_in(byte) != 0) {
468 /*
469 * The input hook indicates that no further processing
470 * should be done by this handler.
471 */
472 return;
473 }
474 #endif
475
476 if (!cmd) {
477 cmd = k_fifo_get(avail_queue, K_NO_WAIT);
478 if (!cmd) {
479 return;
480 }
481 }
482
483 #ifdef CONFIG_UART_CONSOLE_MCUMGR
484 /* Divert this byte from normal console handling if it is part
485 * of an mcumgr frame.
486 */
487 if (handle_mcumgr(cmd, byte)) {
488 continue;
489 }
490 #endif /* CONFIG_UART_CONSOLE_MCUMGR */
491
492 /* Handle ANSI escape mode */
493 if (atomic_test_bit(&esc_state, ESC_ANSI)) {
494 handle_ansi(byte, cmd->line);
495 continue;
496 }
497
498 /* Handle escape mode */
499 if (atomic_test_and_clear_bit(&esc_state, ESC_ESC)) {
500 if (byte == ANSI_ESC) {
501 atomic_set_bit(&esc_state, ESC_ANSI);
502 atomic_set_bit(&esc_state, ESC_ANSI_FIRST);
503 }
504
505 continue;
506 }
507
508 /* Handle special control characters */
509 if (isprint(byte) == 0) {
510 switch (byte) {
511 case BS:
512 case DEL:
513 if (cur > 0) {
514 del_char(&cmd->line[--cur], end);
515 }
516 break;
517 case ESC:
518 atomic_set_bit(&esc_state, ESC_ESC);
519 break;
520 case '\n':
521 if (last_char == '\r') {
522 /* break to avoid double line*/
523 break;
524 }
525 case '\r':
526 cmd->line[cur + end] = '\0';
527 uart_poll_out(uart_console_dev, '\r');
528 uart_poll_out(uart_console_dev, '\n');
529 cur = 0U;
530 end = 0U;
531 k_fifo_put(lines_queue, cmd);
532 cmd = NULL;
533 break;
534 case '\t':
535 if (completion_cb && !end) {
536 cur += completion_cb(cmd->line, cur);
537 }
538 break;
539 default:
540 break;
541 }
542
543 last_char = byte;
544 continue;
545 }
546
547 /* Ignore characters if there's no more buffer space */
548 if (cur + end < sizeof(cmd->line) - 1) {
549 insert_char(&cmd->line[cur++], byte, end);
550 }
551 }
552 }
553
console_input_init(void)554 static void console_input_init(void)
555 {
556 uint8_t c;
557
558 uart_irq_rx_disable(uart_console_dev);
559 uart_irq_tx_disable(uart_console_dev);
560
561 uart_irq_callback_set(uart_console_dev, uart_console_isr);
562
563 /* Drain the fifo */
564 while (uart_irq_rx_ready(uart_console_dev)) {
565 uart_fifo_read(uart_console_dev, &c, 1);
566 }
567
568 uart_irq_rx_enable(uart_console_dev);
569 }
570
uart_register_input(struct k_fifo * avail,struct k_fifo * lines,uint8_t (* completion)(char * str,uint8_t len))571 void uart_register_input(struct k_fifo *avail, struct k_fifo *lines,
572 uint8_t (*completion)(char *str, uint8_t len))
573 {
574 avail_queue = avail;
575 lines_queue = lines;
576 completion_cb = completion;
577
578 console_input_init();
579 }
580
581 #else
uart_register_input(struct k_fifo * avail,struct k_fifo * lines,uint8_t (* completion)(char * str,uint8_t len))582 void uart_register_input(struct k_fifo *avail, struct k_fifo *lines,
583 uint8_t (*completion)(char *str, uint8_t len))
584 {
585 ARG_UNUSED(avail);
586 ARG_UNUSED(lines);
587 ARG_UNUSED(completion);
588 }
589 #endif
590
591 /**
592 * @brief Install printk/stdout hook for UART console output
593 */
594
uart_console_hook_install(void)595 static void uart_console_hook_install(void)
596 {
597 #if defined(CONFIG_STDOUT_CONSOLE)
598 __stdout_hook_install(console_out);
599 #endif
600 #if defined(CONFIG_PRINTK)
601 __printk_hook_install(console_out);
602 #endif
603 }
604
605 /**
606 * @brief Initialize one UART as the console/debug port
607 *
608 * @return 0 if successful, otherwise failed.
609 */
uart_console_init(void)610 static int uart_console_init(void)
611 {
612 if (!device_is_ready(uart_console_dev)) {
613 return -ENODEV;
614 }
615
616 uart_console_hook_install();
617
618 return 0;
619 }
620
621 /* UART console initializes after the UART device itself */
622 SYS_INIT(uart_console_init,
623 #if defined(CONFIG_EARLY_CONSOLE)
624 PRE_KERNEL_1,
625 #else
626 POST_KERNEL,
627 #endif
628 CONFIG_CONSOLE_INIT_PRIORITY);
629