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