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) > 0 &&
450 uart_irq_is_pending(uart_console_dev) > 0) {
451 static struct console_input *cmd;
452 uint8_t byte;
453 int rx;
454
455 rx = uart_irq_rx_ready(uart_console_dev);
456 if (rx < 0) {
457 return;
458 }
459
460 if (rx == 0) {
461 continue;
462 }
463
464 /* Character(s) have been received */
465
466 rx = read_uart(uart_console_dev, &byte, 1);
467 if (rx < 0) {
468 return;
469 }
470
471 #ifdef CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS
472 if (debug_hook_in != NULL && debug_hook_in(byte) != 0) {
473 /*
474 * The input hook indicates that no further processing
475 * should be done by this handler.
476 */
477 return;
478 }
479 #endif
480
481 if (!cmd) {
482 cmd = k_fifo_get(avail_queue, K_NO_WAIT);
483 if (!cmd) {
484 return;
485 }
486 }
487
488 #ifdef CONFIG_UART_CONSOLE_MCUMGR
489 /* Divert this byte from normal console handling if it is part
490 * of an mcumgr frame.
491 */
492 if (handle_mcumgr(cmd, byte)) {
493 continue;
494 }
495 #endif /* CONFIG_UART_CONSOLE_MCUMGR */
496
497 /* Handle ANSI escape mode */
498 if (atomic_test_bit(&esc_state, ESC_ANSI)) {
499 handle_ansi(byte, cmd->line);
500 continue;
501 }
502
503 /* Handle escape mode */
504 if (atomic_test_and_clear_bit(&esc_state, ESC_ESC)) {
505 if (byte == ANSI_ESC) {
506 atomic_set_bit(&esc_state, ESC_ANSI);
507 atomic_set_bit(&esc_state, ESC_ANSI_FIRST);
508 }
509
510 continue;
511 }
512
513 /* Handle special control characters */
514 if (isprint(byte) == 0) {
515 switch (byte) {
516 case BS:
517 case DEL:
518 if (cur > 0) {
519 del_char(&cmd->line[--cur], end);
520 }
521 break;
522 case ESC:
523 atomic_set_bit(&esc_state, ESC_ESC);
524 break;
525 case '\n':
526 if (last_char == '\r') {
527 /* break to avoid double line*/
528 break;
529 }
530 case '\r':
531 cmd->line[cur + end] = '\0';
532 uart_poll_out(uart_console_dev, '\r');
533 uart_poll_out(uart_console_dev, '\n');
534 cur = 0U;
535 end = 0U;
536 k_fifo_put(lines_queue, cmd);
537 cmd = NULL;
538 break;
539 case '\t':
540 if (completion_cb && !end) {
541 cur += completion_cb(cmd->line, cur);
542 }
543 break;
544 default:
545 break;
546 }
547
548 last_char = byte;
549 continue;
550 }
551
552 /* Ignore characters if there's no more buffer space */
553 if (cur + end < sizeof(cmd->line) - 1) {
554 insert_char(&cmd->line[cur++], byte, end);
555 }
556 }
557 }
558
console_input_init(void)559 static void console_input_init(void)
560 {
561 uint8_t c;
562
563 uart_irq_rx_disable(uart_console_dev);
564 uart_irq_tx_disable(uart_console_dev);
565
566 uart_irq_callback_set(uart_console_dev, uart_console_isr);
567
568 /* Drain the fifo */
569 while (uart_irq_rx_ready(uart_console_dev) > 0) {
570 uart_fifo_read(uart_console_dev, &c, 1);
571 }
572
573 uart_irq_rx_enable(uart_console_dev);
574 }
575
uart_register_input(struct k_fifo * avail,struct k_fifo * lines,uint8_t (* completion)(char * str,uint8_t len))576 void uart_register_input(struct k_fifo *avail, struct k_fifo *lines,
577 uint8_t (*completion)(char *str, uint8_t len))
578 {
579 avail_queue = avail;
580 lines_queue = lines;
581 completion_cb = completion;
582
583 console_input_init();
584 }
585
586 #else
uart_register_input(struct k_fifo * avail,struct k_fifo * lines,uint8_t (* completion)(char * str,uint8_t len))587 void uart_register_input(struct k_fifo *avail, struct k_fifo *lines,
588 uint8_t (*completion)(char *str, uint8_t len))
589 {
590 ARG_UNUSED(avail);
591 ARG_UNUSED(lines);
592 ARG_UNUSED(completion);
593 }
594 #endif
595
596 /**
597 * @brief Install printk/stdout hook for UART console output
598 */
599
uart_console_hook_install(void)600 static void uart_console_hook_install(void)
601 {
602 #if defined(CONFIG_STDOUT_CONSOLE)
603 __stdout_hook_install(console_out);
604 #endif
605 #if defined(CONFIG_PRINTK)
606 __printk_hook_install(console_out);
607 #endif
608 }
609
610 /**
611 * @brief Initialize one UART as the console/debug port
612 *
613 * @return 0 if successful, otherwise failed.
614 */
uart_console_init(void)615 static int uart_console_init(void)
616 {
617 if (!device_is_ready(uart_console_dev)) {
618 return -ENODEV;
619 }
620
621 uart_console_hook_install();
622
623 return 0;
624 }
625
626 /* UART console initializes after the UART device itself */
627 SYS_INIT(uart_console_init,
628 #if defined(CONFIG_EARLY_CONSOLE)
629 PRE_KERNEL_1,
630 #else
631 POST_KERNEL,
632 #endif
633 CONFIG_CONSOLE_INIT_PRIORITY);
634