1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <logging/log_backend.h>
8 #include <logging/log_core.h>
9 #include <logging/log_msg.h>
10 #include <logging/log_output.h>
11 #include <logging/log_output_dict.h>
12 #include <logging/log_backend_std.h>
13 #include <device.h>
14 #include <drivers/uart.h>
15 #include <sys/__assert.h>
16 
17 /* Fixed size to avoid auto-added trailing '\0'.
18  * Used if CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX.
19  */
20 static const char LOG_HEX_SEP[10] = "##ZLOGV1##";
21 
22 static const struct device *uart_dev;
23 
char_out(uint8_t * data,size_t length,void * ctx)24 static int char_out(uint8_t *data, size_t length, void *ctx)
25 {
26 	ARG_UNUSED(ctx);
27 
28 	for (size_t i = 0; i < length; i++) {
29 #if defined(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX)
30 		char c;
31 		uint8_t x;
32 
33 		/* upper 8-bit */
34 		x = data[i] >> 4;
35 		(void)hex2char(x, &c);
36 		uart_poll_out(uart_dev, c);
37 
38 		/* lower 8-bit */
39 		x = data[i] & 0x0FU;
40 		(void)hex2char(x, &c);
41 		uart_poll_out(uart_dev, c);
42 #else
43 		uart_poll_out(uart_dev, data[i]);
44 #endif
45 	}
46 
47 	return length;
48 }
49 
50 static uint8_t uart_output_buf;
51 
52 LOG_OUTPUT_DEFINE(log_output_uart, char_out, &uart_output_buf, 1);
53 
put(const struct log_backend * const backend,struct log_msg * msg)54 static void put(const struct log_backend *const backend,
55 		struct log_msg *msg)
56 {
57 	uint32_t flag = IS_ENABLED(CONFIG_LOG_BACKEND_UART_SYST_ENABLE) ?
58 		LOG_OUTPUT_FLAG_FORMAT_SYST : 0;
59 
60 	log_backend_std_put(&log_output_uart, flag, msg);
61 }
62 
process(const struct log_backend * const backend,union log_msg2_generic * msg)63 static void process(const struct log_backend *const backend,
64 		union log_msg2_generic *msg)
65 {
66 	uint32_t flags = log_backend_std_get_flags();
67 
68 	if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY)) {
69 		log_dict_output_msg2_process(&log_output_uart,
70 					     &msg->log, flags);
71 	} else {
72 		log_output_msg2_process(&log_output_uart, &msg->log, flags);
73 	}
74 }
75 
log_backend_uart_init(struct log_backend const * const backend)76 static void log_backend_uart_init(struct log_backend const *const backend)
77 {
78 	uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
79 	__ASSERT_NO_MSG(device_is_ready(uart_dev));
80 
81 	if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX)) {
82 		/* Print a separator so the output can be fed into
83 		 * log parser directly. This is useful when capturing
84 		 * from UART directly where there might be other output
85 		 * (e.g. bootloader).
86 		 */
87 		for (int i = 0; i < sizeof(LOG_HEX_SEP); i++) {
88 			uart_poll_out(uart_dev, LOG_HEX_SEP[i]);
89 		}
90 	}
91 }
92 
panic(struct log_backend const * const backend)93 static void panic(struct log_backend const *const backend)
94 {
95 	log_backend_std_panic(&log_output_uart);
96 }
97 
dropped(const struct log_backend * const backend,uint32_t cnt)98 static void dropped(const struct log_backend *const backend, uint32_t cnt)
99 {
100 	ARG_UNUSED(backend);
101 
102 	if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY)) {
103 		log_dict_output_dropped_process(&log_output_uart, cnt);
104 	} else {
105 		log_backend_std_dropped(&log_output_uart, cnt);
106 	}
107 }
108 
sync_string(const struct log_backend * const backend,struct log_msg_ids src_level,uint32_t timestamp,const char * fmt,va_list ap)109 static void sync_string(const struct log_backend *const backend,
110 		     struct log_msg_ids src_level, uint32_t timestamp,
111 		     const char *fmt, va_list ap)
112 {
113 	uint32_t flag = IS_ENABLED(CONFIG_LOG_BACKEND_UART_SYST_ENABLE) ?
114 		LOG_OUTPUT_FLAG_FORMAT_SYST : 0;
115 
116 	log_backend_std_sync_string(&log_output_uart, flag, src_level,
117 				    timestamp, fmt, ap);
118 }
119 
sync_hexdump(const struct log_backend * const backend,struct log_msg_ids src_level,uint32_t timestamp,const char * metadata,const uint8_t * data,uint32_t length)120 static void sync_hexdump(const struct log_backend *const backend,
121 			 struct log_msg_ids src_level, uint32_t timestamp,
122 			 const char *metadata, const uint8_t *data, uint32_t length)
123 {
124 	uint32_t flag = IS_ENABLED(CONFIG_LOG_BACKEND_UART_SYST_ENABLE) ?
125 		LOG_OUTPUT_FLAG_FORMAT_SYST : 0;
126 
127 	log_backend_std_sync_hexdump(&log_output_uart, flag, src_level,
128 				     timestamp, metadata, data, length);
129 }
130 
131 const struct log_backend_api log_backend_uart_api = {
132 	.process = IS_ENABLED(CONFIG_LOG2) ? process : NULL,
133 	.put = IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) ? put : NULL,
134 	.put_sync_string = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ?
135 			sync_string : NULL,
136 	.put_sync_hexdump = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ?
137 			sync_hexdump : NULL,
138 	.panic = panic,
139 	.init = log_backend_uart_init,
140 	.dropped = IS_ENABLED(CONFIG_LOG_IMMEDIATE) ? NULL : dropped,
141 };
142 
143 LOG_BACKEND_DEFINE(log_backend_uart, log_backend_uart_api, true);
144