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