1 /** @file
2 * @brief Custom logging over UART
3 */
4
5 /*
6 * Copyright (c) 2016 Intel Corporation
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #include <zephyr/types.h>
12 #include <stdbool.h>
13
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <zephyr/drivers/uart_pipe.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/printk-hooks.h>
20 #include <zephyr/sys/libc-hooks.h>
21 #include <zephyr/drivers/uart.h>
22
23 #include <zephyr/logging/log_backend.h>
24 #include <zephyr/logging/log_output.h>
25 #include <zephyr/logging/log_ctrl.h>
26 #include <zephyr/logging/log.h>
27
28 #include <zephyr/bluetooth/buf.h>
29
30 #include "monitor.h"
31
32 /* This is the same default priority as for other console handlers,
33 * except that we're not exporting it as a Kconfig variable until a
34 * clear need arises.
35 */
36 #define MONITOR_INIT_PRIORITY 60
37
38 /* These defines follow the values used by syslog(2) */
39 #define BT_LOG_ERR 3
40 #define BT_LOG_WARN 4
41 #define BT_LOG_INFO 6
42 #define BT_LOG_DBG 7
43
44 /* TS resolution is 1/10th of a millisecond */
45 #define MONITOR_TS_FREQ 10000
46
47 /* Maximum (string) length of a log message */
48 #define MONITOR_MSG_MAX 128
49
50 enum {
51 BT_LOG_BUSY,
52 BT_CONSOLE_BUSY,
53 };
54
55 static atomic_t flags;
56
57 static struct {
58 atomic_t cmd;
59 atomic_t evt;
60 atomic_t acl_tx;
61 atomic_t acl_rx;
62 #if defined(CONFIG_BT_CLASSIC)
63 atomic_t sco_tx;
64 atomic_t sco_rx;
65 #endif
66 atomic_t other;
67 } drops;
68
drop_add(uint16_t opcode)69 static void drop_add(uint16_t opcode)
70 {
71 switch (opcode) {
72 case BT_MONITOR_COMMAND_PKT:
73 atomic_inc(&drops.cmd);
74 break;
75 case BT_MONITOR_EVENT_PKT:
76 atomic_inc(&drops.evt);
77 break;
78 case BT_MONITOR_ACL_TX_PKT:
79 atomic_inc(&drops.acl_tx);
80 break;
81 case BT_MONITOR_ACL_RX_PKT:
82 atomic_inc(&drops.acl_rx);
83 break;
84 #if defined(CONFIG_BT_CLASSIC)
85 case BT_MONITOR_SCO_TX_PKT:
86 atomic_inc(&drops.sco_tx);
87 break;
88 case BT_MONITOR_SCO_RX_PKT:
89 atomic_inc(&drops.sco_rx);
90 break;
91 #endif
92 default:
93 atomic_inc(&drops.other);
94 break;
95 }
96 }
97
98 #if defined(CONFIG_BT_DEBUG_MONITOR_RTT)
99 #include <SEGGER_RTT.h>
100
101 static bool panic_mode;
102
103 #define RTT_BUFFER_NAME CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER_NAME
104 #define RTT_BUF_SIZE CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER_SIZE
105
monitor_send(const void * data,size_t len)106 static void monitor_send(const void *data, size_t len)
107 {
108 static uint8_t rtt_buf[RTT_BUF_SIZE];
109 static size_t rtt_buf_offset;
110 struct bt_monitor_hdr *hdr;
111 unsigned int cnt = 0;
112 bool drop;
113
114 /* Drop any packet which cannot fit the buffer */
115 drop = rtt_buf_offset + len > sizeof(rtt_buf);
116 if (!drop) {
117 (void)memcpy(rtt_buf + rtt_buf_offset, data, len);
118 }
119
120 rtt_buf_offset += len;
121
122 /* Check if the packet is complete */
123 hdr = (struct bt_monitor_hdr *)rtt_buf;
124 if (rtt_buf_offset < sizeof(hdr->data_len) + hdr->data_len) {
125 return;
126 }
127
128 if (!drop) {
129 if (panic_mode) {
130 cnt = SEGGER_RTT_WriteNoLock(CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER,
131 rtt_buf, rtt_buf_offset);
132 } else {
133 cnt = SEGGER_RTT_Write(CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER,
134 rtt_buf, rtt_buf_offset);
135 }
136 }
137
138 if (!cnt) {
139 drop_add(hdr->opcode);
140 }
141
142 /* Prepare for the next packet */
143 rtt_buf_offset = 0;
144 }
145
poll_out(char c)146 static void poll_out(char c)
147 {
148 monitor_send(&c, sizeof(c));
149 }
150 #elif defined(CONFIG_BT_DEBUG_MONITOR_UART)
151 static const struct device *const monitor_dev =
152 #if DT_HAS_CHOSEN(zephyr_bt_mon_uart)
153 DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_mon_uart));
154 #elif !defined(CONFIG_UART_CONSOLE) && DT_HAS_CHOSEN(zephyr_console)
155 /* Fall back to console UART if it's available */
156 DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
157 #else
158 NULL;
159 #error "BT_DEBUG_MONITOR_UART enabled but no UART specified"
160 #endif
161
poll_out(char c)162 static void poll_out(char c)
163 {
164 uart_poll_out(monitor_dev, c);
165 }
166
monitor_send(const void * data,size_t len)167 static void monitor_send(const void *data, size_t len)
168 {
169 const uint8_t *buf = data;
170
171 while (len--) {
172 poll_out(*buf++);
173 }
174 }
175 #endif /* CONFIG_BT_DEBUG_MONITOR_UART */
176
encode_drops(struct bt_monitor_hdr * hdr,uint8_t type,atomic_t * val)177 static void encode_drops(struct bt_monitor_hdr *hdr, uint8_t type,
178 atomic_t *val)
179 {
180 atomic_val_t count;
181
182 count = atomic_set(val, 0);
183 if (count) {
184 hdr->ext[hdr->hdr_len++] = type;
185 hdr->ext[hdr->hdr_len++] = MIN(count, 255);
186 }
187 }
188
monitor_ts_get(void)189 static uint32_t monitor_ts_get(void)
190 {
191 uint64_t cycle;
192
193 if (IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) {
194 cycle = k_cycle_get_64();
195 } else {
196 cycle = k_cycle_get_32();
197 }
198
199 return (cycle / (sys_clock_hw_cycles_per_sec() / MONITOR_TS_FREQ));
200 }
201
encode_hdr(struct bt_monitor_hdr * hdr,uint32_t timestamp,uint16_t opcode,uint16_t len)202 static inline void encode_hdr(struct bt_monitor_hdr *hdr, uint32_t timestamp,
203 uint16_t opcode, uint16_t len)
204 {
205 struct bt_monitor_ts32 *ts;
206
207 hdr->opcode = sys_cpu_to_le16(opcode);
208 hdr->flags = 0U;
209
210 ts = (void *)hdr->ext;
211 ts->type = BT_MONITOR_TS32;
212 ts->ts32 = timestamp;
213 hdr->hdr_len = sizeof(*ts);
214
215 encode_drops(hdr, BT_MONITOR_COMMAND_DROPS, &drops.cmd);
216 encode_drops(hdr, BT_MONITOR_EVENT_DROPS, &drops.evt);
217 encode_drops(hdr, BT_MONITOR_ACL_TX_DROPS, &drops.acl_tx);
218 encode_drops(hdr, BT_MONITOR_ACL_RX_DROPS, &drops.acl_rx);
219 #if defined(CONFIG_BT_CLASSIC)
220 encode_drops(hdr, BT_MONITOR_SCO_TX_DROPS, &drops.sco_tx);
221 encode_drops(hdr, BT_MONITOR_SCO_RX_DROPS, &drops.sco_rx);
222 #endif
223 encode_drops(hdr, BT_MONITOR_OTHER_DROPS, &drops.other);
224
225 hdr->data_len = sys_cpu_to_le16(4 + hdr->hdr_len + len);
226 }
227
bt_monitor_send(uint16_t opcode,const void * data,size_t len)228 void bt_monitor_send(uint16_t opcode, const void *data, size_t len)
229 {
230 struct bt_monitor_hdr hdr;
231
232 if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
233 drop_add(opcode);
234 return;
235 }
236
237 encode_hdr(&hdr, monitor_ts_get(), opcode, len);
238
239 monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
240 monitor_send(data, len);
241
242 atomic_clear_bit(&flags, BT_LOG_BUSY);
243 }
244
bt_monitor_new_index(uint8_t type,uint8_t bus,const bt_addr_t * addr,const char * name)245 void bt_monitor_new_index(uint8_t type, uint8_t bus, const bt_addr_t *addr,
246 const char *name)
247 {
248 struct bt_monitor_new_index pkt;
249
250 pkt.type = type;
251 pkt.bus = bus;
252 memcpy(pkt.bdaddr, addr, 6);
253 strncpy(pkt.name, name, sizeof(pkt.name) - 1);
254 pkt.name[sizeof(pkt.name) - 1] = '\0';
255
256 bt_monitor_send(BT_MONITOR_NEW_INDEX, &pkt, sizeof(pkt));
257 }
258
259 #if !defined(CONFIG_UART_CONSOLE) && !defined(CONFIG_RTT_CONSOLE) && !defined(CONFIG_LOG_PRINTK)
monitor_console_out(int c)260 static int monitor_console_out(int c)
261 {
262 static char buf[MONITOR_MSG_MAX];
263 static size_t len;
264
265 if (atomic_test_and_set_bit(&flags, BT_CONSOLE_BUSY)) {
266 return c;
267 }
268
269 if (c != '\n' && len < sizeof(buf) - 1) {
270 buf[len++] = c;
271 atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
272 return c;
273 }
274
275 buf[len++] = '\0';
276
277 bt_monitor_send(BT_MONITOR_SYSTEM_NOTE, buf, len);
278 len = 0;
279
280 atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
281
282 return c;
283 }
284 #endif /* !CONFIG_UART_CONSOLE && !CONFIG_RTT_CONSOLE && !CONFIG_LOG_PRINTK */
285
286 #ifndef CONFIG_LOG_MODE_MINIMAL
287 struct monitor_log_ctx {
288 size_t total_len;
289 char msg[MONITOR_MSG_MAX];
290 };
291
monitor_log_out(uint8_t * data,size_t length,void * user_data)292 static int monitor_log_out(uint8_t *data, size_t length, void *user_data)
293 {
294 struct monitor_log_ctx *ctx = user_data;
295 size_t i;
296
297 for (i = 0; i < length && ctx->total_len < sizeof(ctx->msg); i++) {
298 /* With CONFIG_LOG_PRINTK the line terminator will come as
299 * as part of messages.
300 */
301 if (IS_ENABLED(CONFIG_LOG_PRINTK) &&
302 (data[i] == '\r' || data[i] == '\n')) {
303 break;
304 }
305
306 ctx->msg[ctx->total_len++] = data[i];
307 }
308
309 return length;
310 }
311
312 static uint8_t buf;
313
314 LOG_OUTPUT_DEFINE(monitor_log_output, monitor_log_out, &buf, 1);
315
monitor_priority_get(uint8_t log_level)316 static inline uint8_t monitor_priority_get(uint8_t log_level)
317 {
318 static const uint8_t prios[] = {
319 [LOG_LEVEL_NONE] = 0,
320 [LOG_LEVEL_ERR] = BT_LOG_ERR,
321 [LOG_LEVEL_WRN] = BT_LOG_WARN,
322 [LOG_LEVEL_INF] = BT_LOG_INFO,
323 [LOG_LEVEL_DBG] = BT_LOG_DBG,
324 };
325
326 if (log_level < ARRAY_SIZE(prios)) {
327 return prios[log_level];
328 }
329
330 return BT_LOG_DBG;
331 }
332
monitor_log_process(const struct log_backend * const backend,union log_msg_generic * msg)333 static void monitor_log_process(const struct log_backend *const backend,
334 union log_msg_generic *msg)
335 {
336 struct bt_monitor_user_logging user_log;
337 struct monitor_log_ctx ctx;
338 struct bt_monitor_hdr hdr;
339 static const char id[] = "bt";
340
341 log_output_ctx_set(&monitor_log_output, &ctx);
342
343 ctx.total_len = 0;
344 log_output_msg_process(&monitor_log_output, &msg->log,
345 LOG_OUTPUT_FLAG_CRLF_NONE);
346
347 if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
348 drop_add(BT_MONITOR_USER_LOGGING);
349 return;
350 }
351
352 encode_hdr(&hdr, (uint32_t)log_msg_get_timestamp(&msg->log),
353 BT_MONITOR_USER_LOGGING,
354 sizeof(user_log) + sizeof(id) + ctx.total_len + 1);
355
356 user_log.priority = monitor_priority_get(log_msg_get_level(&msg->log));
357 user_log.ident_len = sizeof(id);
358
359 monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
360 monitor_send(&user_log, sizeof(user_log));
361 monitor_send(id, sizeof(id));
362 monitor_send(ctx.msg, ctx.total_len);
363
364 /* Terminate the string with null */
365 poll_out('\0');
366
367 atomic_clear_bit(&flags, BT_LOG_BUSY);
368 }
369
monitor_log_panic(const struct log_backend * const backend)370 static void monitor_log_panic(const struct log_backend *const backend)
371 {
372 #if defined(CONFIG_BT_DEBUG_MONITOR_RTT)
373 panic_mode = true;
374 #endif
375 }
376
monitor_log_init(const struct log_backend * const backend)377 static void monitor_log_init(const struct log_backend *const backend)
378 {
379 log_set_timestamp_func(monitor_ts_get, MONITOR_TS_FREQ);
380 }
381
382 static const struct log_backend_api monitor_log_api = {
383 .process = monitor_log_process,
384 .panic = monitor_log_panic,
385 .init = monitor_log_init,
386 };
387
388 LOG_BACKEND_DEFINE(bt_monitor, monitor_log_api, true);
389 #endif /* CONFIG_LOG_MODE_MINIMAL */
390
bt_monitor_init(void)391 static int bt_monitor_init(void)
392 {
393
394 #if defined(CONFIG_BT_DEBUG_MONITOR_RTT)
395 static uint8_t rtt_up_buf[RTT_BUF_SIZE];
396
397 SEGGER_RTT_ConfigUpBuffer(CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER,
398 RTT_BUFFER_NAME, rtt_up_buf, RTT_BUF_SIZE,
399 SEGGER_RTT_MODE_NO_BLOCK_SKIP);
400 #elif defined(CONFIG_BT_DEBUG_MONITOR_UART)
401 __ASSERT_NO_MSG(device_is_ready(monitor_dev));
402
403 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
404 uart_irq_rx_disable(monitor_dev);
405 uart_irq_tx_disable(monitor_dev);
406 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
407 #endif /* CONFIG_BT_DEBUG_MONITOR_UART */
408
409 #if !defined(CONFIG_UART_CONSOLE) && !defined(CONFIG_RTT_CONSOLE) && !defined(CONFIG_LOG_PRINTK)
410 __printk_hook_install(monitor_console_out);
411 __stdout_hook_install(monitor_console_out);
412 #endif /* !CONFIG_UART_CONSOLE && !CONFIG_RTT_CONSOLE && !CONFIG_LOG_PRINTK */
413
414 return 0;
415 }
416
417 SYS_INIT(bt_monitor_init, PRE_KERNEL_1, MONITOR_INIT_PRIORITY);
418