/** @file * @brief Custom logging over UART */ /* * Copyright (c) 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "monitor.h" /* This is the same default priority as for other console handlers, * except that we're not exporting it as a Kconfig variable until a * clear need arises. */ #define MONITOR_INIT_PRIORITY 60 static struct device *monitor_dev; extern int _prf(int (*func)(), void *dest, const char *format, va_list vargs); static void monitor_send(const void *data, size_t len) { const uint8_t *buf = data; while (len--) { uart_poll_out(monitor_dev, *buf++); } } static inline void encode_hdr(struct bt_monitor_hdr *hdr, uint16_t opcode, uint16_t len) { uint32_t ts32; hdr->hdr_len = sizeof(hdr->type) + sizeof(hdr->ts32); hdr->data_len = sys_cpu_to_le16(4 + hdr->hdr_len + len); hdr->opcode = sys_cpu_to_le16(opcode); hdr->flags = 0; /* Extended header */ hdr->type = BT_MONITOR_TS32; ts32 = sys_tick_get_32() * sys_clock_us_per_tick / 100; hdr->ts32 = sys_cpu_to_le32(ts32); } static int log_out(int c, void *unused) { uart_poll_out(monitor_dev, c); return 0; } void bt_log(int prio, const char *fmt, ...) { struct bt_monitor_user_logging log; struct bt_monitor_hdr hdr; const char id[] = "bt"; va_list ap; int len, key; va_start(ap, fmt); len = vsnprintf(NULL, 0, fmt, ap); va_end(ap); if (len < 0) { return; } log.priority = prio; log.ident_len = sizeof(id); encode_hdr(&hdr, BT_MONITOR_USER_LOGGING, sizeof(log) + sizeof(id) + len + 1); key = irq_lock(); monitor_send(&hdr, sizeof(hdr)); monitor_send(&log, sizeof(log)); monitor_send(id, sizeof(id)); va_start(ap, fmt); _prf(log_out, NULL, fmt, ap); va_end(ap); /* Terminate the string with null */ uart_poll_out(monitor_dev, '\0'); irq_unlock(key); } void bt_monitor_send(uint16_t opcode, const void *data, size_t len) { struct bt_monitor_hdr hdr; int key; encode_hdr(&hdr, opcode, len); key = irq_lock(); monitor_send(&hdr, sizeof(hdr)); monitor_send(data, len); irq_unlock(key); } void bt_monitor_new_index(uint8_t type, uint8_t bus, bt_addr_t *addr, const char *name) { struct bt_monitor_new_index pkt; pkt.type = type; pkt.bus = bus; memcpy(pkt.bdaddr, addr, 6); strncpy(pkt.name, name, sizeof(pkt.name) - 1); pkt.name[sizeof(pkt.name) - 1] = '\0'; bt_monitor_send(BT_MONITOR_NEW_INDEX, &pkt, sizeof(pkt)); } #if !defined(CONFIG_UART_CONSOLE) static int monitor_console_out(int c) { static char buf[128]; static size_t len; int key; key = irq_lock(); if (c != '\n' && len < sizeof(buf) - 1) { buf[len++] = c; irq_unlock(key); return c; } buf[len++] = '\0'; bt_monitor_send(BT_MONITOR_SYSTEM_NOTE, buf, len); len = 0; irq_unlock(key); return c; } extern void __printk_hook_install(int (*fn)(int)); extern void __stdout_hook_install(int (*fn)(int)); #endif /* !CONFIG_UART_CONSOLE */ static int bt_monitor_init(struct device *d) { ARG_UNUSED(d); monitor_dev = device_get_binding(CONFIG_BLUETOOTH_MONITOR_ON_DEV_NAME); uart_irq_rx_disable(monitor_dev); uart_irq_tx_disable(monitor_dev); #if !defined(CONFIG_UART_CONSOLE) __printk_hook_install(monitor_console_out); __stdout_hook_install(monitor_console_out); #endif return 0; } SYS_INIT(bt_monitor_init, PRIMARY, MONITOR_INIT_PRIORITY);