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 SEGGER_RTT_LOCK();
131 }
132 cnt = SEGGER_RTT_WriteNoLock(CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER,
133 rtt_buf, rtt_buf_offset);
134 if (!panic_mode) {
135 SEGGER_RTT_UNLOCK();
136 }
137 }
138
139 if (!cnt) {
140 drop_add(hdr->opcode);
141 }
142
143 /* Prepare for the next packet */
144 rtt_buf_offset = 0;
145 }
146
poll_out(char c)147 static void poll_out(char c)
148 {
149 monitor_send(&c, sizeof(c));
150 }
151 #elif defined(CONFIG_BT_DEBUG_MONITOR_UART)
152 static const struct device *const monitor_dev =
153 #if DT_HAS_CHOSEN(zephyr_bt_mon_uart)
154 DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_mon_uart));
155 #elif !defined(CONFIG_UART_CONSOLE) && DT_HAS_CHOSEN(zephyr_console)
156 /* Fall back to console UART if it's available */
157 DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
158 #else
159 NULL;
160 #error "BT_DEBUG_MONITOR_UART enabled but no UART specified"
161 #endif
162
poll_out(char c)163 static void poll_out(char c)
164 {
165 uart_poll_out(monitor_dev, c);
166 }
167
monitor_send(const void * data,size_t len)168 static void monitor_send(const void *data, size_t len)
169 {
170 const uint8_t *buf = data;
171
172 while (len--) {
173 poll_out(*buf++);
174 }
175 }
176 #endif /* CONFIG_BT_DEBUG_MONITOR_UART */
177
encode_drops(struct bt_monitor_hdr * hdr,uint8_t type,atomic_t * val)178 static void encode_drops(struct bt_monitor_hdr *hdr, uint8_t type,
179 atomic_t *val)
180 {
181 atomic_val_t count;
182
183 count = atomic_set(val, 0);
184 if (count) {
185 hdr->ext[hdr->hdr_len++] = type;
186 hdr->ext[hdr->hdr_len++] = MIN(count, 255);
187 }
188 }
189
monitor_ts_get(void)190 static uint32_t monitor_ts_get(void)
191 {
192 uint64_t cycle;
193
194 if (IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) {
195 cycle = k_cycle_get_64();
196 } else {
197 cycle = k_cycle_get_32();
198 }
199
200 return (cycle / (sys_clock_hw_cycles_per_sec() / MONITOR_TS_FREQ));
201 }
202
encode_hdr(struct bt_monitor_hdr * hdr,uint32_t timestamp,uint16_t opcode,uint16_t len)203 static inline void encode_hdr(struct bt_monitor_hdr *hdr, uint32_t timestamp,
204 uint16_t opcode, uint16_t len)
205 {
206 struct bt_monitor_ts32 *ts;
207
208 hdr->opcode = sys_cpu_to_le16(opcode);
209 hdr->flags = 0U;
210
211 ts = (void *)hdr->ext;
212 ts->type = BT_MONITOR_TS32;
213 ts->ts32 = timestamp;
214 hdr->hdr_len = sizeof(*ts);
215
216 encode_drops(hdr, BT_MONITOR_COMMAND_DROPS, &drops.cmd);
217 encode_drops(hdr, BT_MONITOR_EVENT_DROPS, &drops.evt);
218 encode_drops(hdr, BT_MONITOR_ACL_TX_DROPS, &drops.acl_tx);
219 encode_drops(hdr, BT_MONITOR_ACL_RX_DROPS, &drops.acl_rx);
220 #if defined(CONFIG_BT_CLASSIC)
221 encode_drops(hdr, BT_MONITOR_SCO_TX_DROPS, &drops.sco_tx);
222 encode_drops(hdr, BT_MONITOR_SCO_RX_DROPS, &drops.sco_rx);
223 #endif
224 encode_drops(hdr, BT_MONITOR_OTHER_DROPS, &drops.other);
225
226 hdr->data_len = sys_cpu_to_le16(4 + hdr->hdr_len + len);
227 }
228
bt_monitor_send(uint16_t opcode,const void * data,size_t len)229 void bt_monitor_send(uint16_t opcode, const void *data, size_t len)
230 {
231 struct bt_monitor_hdr hdr;
232
233 if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
234 drop_add(opcode);
235 return;
236 }
237
238 encode_hdr(&hdr, monitor_ts_get(), opcode, len);
239
240 monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
241 monitor_send(data, len);
242
243 atomic_clear_bit(&flags, BT_LOG_BUSY);
244 }
245
bt_monitor_new_index(uint8_t type,uint8_t bus,const bt_addr_t * addr,const char * name)246 void bt_monitor_new_index(uint8_t type, uint8_t bus, const bt_addr_t *addr,
247 const char *name)
248 {
249 struct bt_monitor_new_index pkt;
250
251 pkt.type = type;
252 pkt.bus = bus;
253 memcpy(pkt.bdaddr, addr, 6);
254 strncpy(pkt.name, name, sizeof(pkt.name) - 1);
255 pkt.name[sizeof(pkt.name) - 1] = '\0';
256
257 bt_monitor_send(BT_MONITOR_NEW_INDEX, &pkt, sizeof(pkt));
258 }
259
260 #if !defined(CONFIG_UART_CONSOLE) && !defined(CONFIG_RTT_CONSOLE) && !defined(CONFIG_LOG_PRINTK)
monitor_console_out(int c)261 static int monitor_console_out(int c)
262 {
263 static char buf[MONITOR_MSG_MAX];
264 static size_t len;
265
266 if (atomic_test_and_set_bit(&flags, BT_CONSOLE_BUSY)) {
267 return c;
268 }
269
270 if (c != '\n' && len < sizeof(buf) - 1) {
271 buf[len++] = c;
272 atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
273 return c;
274 }
275
276 buf[len++] = '\0';
277
278 bt_monitor_send(BT_MONITOR_SYSTEM_NOTE, buf, len);
279 len = 0;
280
281 atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
282
283 return c;
284 }
285 #endif /* !CONFIG_UART_CONSOLE && !CONFIG_RTT_CONSOLE && !CONFIG_LOG_PRINTK */
286
287 #ifndef CONFIG_LOG_MODE_MINIMAL
288 struct monitor_log_ctx {
289 size_t total_len;
290 char msg[MONITOR_MSG_MAX];
291 };
292
monitor_log_out(uint8_t * data,size_t length,void * user_data)293 static int monitor_log_out(uint8_t *data, size_t length, void *user_data)
294 {
295 struct monitor_log_ctx *ctx = user_data;
296 size_t i;
297
298 for (i = 0; i < length && ctx->total_len < sizeof(ctx->msg); i++) {
299 /* With CONFIG_LOG_PRINTK the line terminator will come as
300 * as part of messages.
301 */
302 if (IS_ENABLED(CONFIG_LOG_PRINTK) &&
303 (data[i] == '\r' || data[i] == '\n')) {
304 break;
305 }
306
307 ctx->msg[ctx->total_len++] = data[i];
308 }
309
310 return length;
311 }
312
313 static uint8_t buf;
314
315 LOG_OUTPUT_DEFINE(monitor_log_output, monitor_log_out, &buf, 1);
316
monitor_priority_get(uint8_t log_level)317 static inline uint8_t monitor_priority_get(uint8_t log_level)
318 {
319 static const uint8_t prios[] = {
320 [LOG_LEVEL_NONE] = 0,
321 [LOG_LEVEL_ERR] = BT_LOG_ERR,
322 [LOG_LEVEL_WRN] = BT_LOG_WARN,
323 [LOG_LEVEL_INF] = BT_LOG_INFO,
324 [LOG_LEVEL_DBG] = BT_LOG_DBG,
325 };
326
327 if (log_level < ARRAY_SIZE(prios)) {
328 return prios[log_level];
329 }
330
331 return BT_LOG_DBG;
332 }
333
monitor_log_process(const struct log_backend * const backend,union log_msg_generic * msg)334 static void monitor_log_process(const struct log_backend *const backend,
335 union log_msg_generic *msg)
336 {
337 struct bt_monitor_user_logging user_log;
338 struct monitor_log_ctx ctx;
339 struct bt_monitor_hdr hdr;
340 static const char id[] = "bt";
341
342 log_output_ctx_set(&monitor_log_output, &ctx);
343
344 ctx.total_len = 0;
345 log_output_msg_process(&monitor_log_output, &msg->log,
346 LOG_OUTPUT_FLAG_CRLF_NONE);
347
348 if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
349 drop_add(BT_MONITOR_USER_LOGGING);
350 return;
351 }
352
353 encode_hdr(&hdr, (uint32_t)log_msg_get_timestamp(&msg->log),
354 BT_MONITOR_USER_LOGGING,
355 sizeof(user_log) + sizeof(id) + ctx.total_len + 1);
356
357 user_log.priority = monitor_priority_get(log_msg_get_level(&msg->log));
358 user_log.ident_len = sizeof(id);
359
360 monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
361 monitor_send(&user_log, sizeof(user_log));
362 monitor_send(id, sizeof(id));
363 monitor_send(ctx.msg, ctx.total_len);
364
365 /* Terminate the string with null */
366 poll_out('\0');
367
368 atomic_clear_bit(&flags, BT_LOG_BUSY);
369 }
370
monitor_log_panic(const struct log_backend * const backend)371 static void monitor_log_panic(const struct log_backend *const backend)
372 {
373 #if defined(CONFIG_BT_DEBUG_MONITOR_RTT)
374 panic_mode = true;
375 #endif
376 }
377
monitor_log_init(const struct log_backend * const backend)378 static void monitor_log_init(const struct log_backend *const backend)
379 {
380 log_set_timestamp_func(monitor_ts_get, MONITOR_TS_FREQ);
381 }
382
383 static const struct log_backend_api monitor_log_api = {
384 .process = monitor_log_process,
385 .panic = monitor_log_panic,
386 .init = monitor_log_init,
387 };
388
389 LOG_BACKEND_DEFINE(bt_monitor, monitor_log_api, true);
390 #endif /* CONFIG_LOG_MODE_MINIMAL */
391
bt_monitor_init(void)392 static int bt_monitor_init(void)
393 {
394
395 #if defined(CONFIG_BT_DEBUG_MONITOR_RTT)
396 static uint8_t rtt_up_buf[RTT_BUF_SIZE];
397
398 SEGGER_RTT_ConfigUpBuffer(CONFIG_BT_DEBUG_MONITOR_RTT_BUFFER,
399 RTT_BUFFER_NAME, rtt_up_buf, RTT_BUF_SIZE,
400 SEGGER_RTT_MODE_NO_BLOCK_SKIP);
401 #elif defined(CONFIG_BT_DEBUG_MONITOR_UART)
402 __ASSERT_NO_MSG(device_is_ready(monitor_dev));
403
404 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
405 uart_irq_rx_disable(monitor_dev);
406 uart_irq_tx_disable(monitor_dev);
407 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
408 #endif /* CONFIG_BT_DEBUG_MONITOR_UART */
409
410 #if !defined(CONFIG_UART_CONSOLE) && !defined(CONFIG_RTT_CONSOLE) && !defined(CONFIG_LOG_PRINTK)
411 __printk_hook_install(monitor_console_out);
412 __stdout_hook_install(monitor_console_out);
413 #endif /* !CONFIG_UART_CONSOLE && !CONFIG_RTT_CONSOLE && !CONFIG_LOG_PRINTK */
414
415 return 0;
416 }
417
418 SYS_INIT(bt_monitor_init, PRE_KERNEL_1, MONITOR_INIT_PRIORITY);
419