logging: Added BLE Backend Service
Added a new logger backend to recieve data over a BLE notification characteristic. The characteristic is based on the UUID from the Nordic connect SDK service NUS, which allows to have a UART shell over BLE. The idea behind this, is that this logger can be used directly with the NRF apps or any other BLE UART terminal app. Signed-off-by: Victor Chavez <chavez-bermudez@fh-aachen.de>
This commit is contained in:
parent
872907f42c
commit
a18aa915ce
10 changed files with 388 additions and 0 deletions
42
include/zephyr/logging/log_backend_ble.h
Normal file
42
include/zephyr/logging/log_backend_ble.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Victor Chavez
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_LOG_BACKEND_BLE_H_
|
||||
#define ZEPHYR_LOG_BACKEND_BLE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
/**
|
||||
* @brief Raw adv UUID data to add the ble backend for the use with apps
|
||||
* such as the NRF Toolbox
|
||||
*
|
||||
*/
|
||||
|
||||
#define LOGGER_BACKEND_BLE_ADV_UUID_DATA \
|
||||
0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, \
|
||||
0x6E
|
||||
|
||||
/**
|
||||
* @brief Hook for application to know when the ble backend
|
||||
* is enabled or disabled.
|
||||
* @param backend_status True if the backend is enabled or false if disabled
|
||||
* @param ctx User context
|
||||
*
|
||||
*/
|
||||
typedef void (*logger_backend_ble_hook)(bool backend_status, void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Allows application to add a hook for the status of the BLE
|
||||
* logger backend.
|
||||
* @details The BLE logger backend is enabled or disabled auomatically by
|
||||
* the subscription of the notification characteristic of this BLE
|
||||
* Logger backend service.
|
||||
*
|
||||
* @param hook The hook that will be called when the status of the backend changes
|
||||
* @param ctx User context for whenever the hook is called
|
||||
*/
|
||||
void logger_backend_ble_set_hook(logger_backend_ble_hook hook, void *ctx);
|
||||
|
||||
#endif /* ZEPHYR_LOG_BACKEND_BLE_H_ */
|
||||
10
samples/subsys/logging/ble_backend/CMakeLists.txt
Normal file
10
samples/subsys/logging/ble_backend/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(logger_ble_backend)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
)
|
||||
26
samples/subsys/logging/ble_backend/README.rst
Normal file
26
samples/subsys/logging/ble_backend/README.rst
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
.. _logger_ble_backend:
|
||||
|
||||
Logging: BLE Backend
|
||||
########################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Sample that demonstrates how to setup and use the BLE Logging backend. The
|
||||
BLE Logger uses the NRF Connect SDK NUS service as UUID to make it compatible
|
||||
with already existing apps to debug BLE connections over UART.
|
||||
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
* A board with BLE support
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
This sample can be found under :zephyr_file:`samples/subsys/logging/ble_backend` in the
|
||||
Zephyr tree.
|
||||
|
||||
The BLE logger can be tested with the NRF Toolbox app or any similar app that can connect over
|
||||
BLE and detect the NRF NUS UUID service.
|
||||
11
samples/subsys/logging/ble_backend/prj.conf
Normal file
11
samples/subsys/logging/ble_backend/prj.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_DEVICE_NAME="Zephyr Logger Backend BLE"
|
||||
CONFIG_LOG_BACKEND_BLE=y
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=2048
|
||||
# Uncomment to use the maximum buffer size
|
||||
# CONFIG_BT_L2CAP_TX_MTU=600
|
||||
# CONFIG_BT_BUF_ACL_RX_SIZE=600
|
||||
# CONFIG_LOG_BACKEND_BLE_BUF_SIZE=512
|
||||
11
samples/subsys/logging/ble_backend/sample.yaml
Normal file
11
samples/subsys/logging/ble_backend/sample.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
sample:
|
||||
description: A simple application that demonstrates the
|
||||
use of the logging ble backend.
|
||||
name: logger backend ble
|
||||
tests:
|
||||
sample.logging.ble_backend.nrf52833:
|
||||
harness: bluetooth
|
||||
platform_allow: qemu_cortex_m3 qemu_x86
|
||||
integration_platforms:
|
||||
- qemu_cortex_m3
|
||||
tags: bluetooth
|
||||
100
samples/subsys/logging/ble_backend/src/main.c
Normal file
100
samples/subsys/logging/ble_backend/src/main.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Victor Chavez
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/logging/log_backend_ble.h>
|
||||
|
||||
LOG_MODULE_REGISTER(ble_backend);
|
||||
|
||||
|
||||
static const struct bt_data ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_DATA_BYTES(BT_DATA_UUID128_ALL, LOGGER_BACKEND_BLE_ADV_UUID_DATA)
|
||||
};
|
||||
|
||||
static void start_adv(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||
if (err) {
|
||||
LOG_ERR("Advertising failed to start (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INF("Advertising successfully started");
|
||||
}
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t err)
|
||||
{
|
||||
if (err) {
|
||||
LOG_ERR("Connection failed (err 0x%02x)", err);
|
||||
} else {
|
||||
LOG_INF("Connected");
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
LOG_INF("Disconnected (reason 0x%02x)", reason);
|
||||
start_adv();
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
};
|
||||
|
||||
static void auth_cancel(struct bt_conn *conn)
|
||||
{
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
LOG_INF("Pairing cancelled: %s", addr);
|
||||
}
|
||||
|
||||
static struct bt_conn_auth_cb auth_cb_display = {
|
||||
.cancel = auth_cancel,
|
||||
};
|
||||
|
||||
void backend_ble_hook(bool status, void *ctx)
|
||||
{
|
||||
ARG_UNUSED(ctx);
|
||||
|
||||
if (status) {
|
||||
LOG_INF("BLE Logger Backend enabled.");
|
||||
} else {
|
||||
LOG_INF("BLE Logger Backend disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_INF("BLE LOG Demo");
|
||||
logger_backend_ble_set_hook(backend_ble_hook, NULL);
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
LOG_ERR("Bluetooth init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_conn_auth_cb_register(&auth_cb_display);
|
||||
|
||||
start_adv();
|
||||
|
||||
while (1) {
|
||||
uint32_t uptime_secs = k_uptime_get_32()/1000U;
|
||||
|
||||
LOG_INF("Uptime %d secs", uptime_secs);
|
||||
k_sleep(K_MSEC(1000));
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,11 @@ zephyr_sources_ifdef(
|
|||
log_backend_adsp_mtrace.c
|
||||
)
|
||||
|
||||
zephyr_sources_ifdef(
|
||||
CONFIG_LOG_BACKEND_BLE
|
||||
log_backend_ble.c
|
||||
)
|
||||
|
||||
zephyr_sources_ifdef(
|
||||
CONFIG_LOG_BACKEND_EFI_CONSOLE
|
||||
log_backend_efi_console.c
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ menu "Backends"
|
|||
rsource "Kconfig.adsp"
|
||||
rsource "Kconfig.adsp_hda"
|
||||
rsource "Kconfig.adsp_mtrace"
|
||||
rsource "Kconfig.ble"
|
||||
rsource "Kconfig.efi_console"
|
||||
rsource "Kconfig.fs"
|
||||
rsource "Kconfig.native_posix"
|
||||
|
|
|
|||
34
subsys/logging/backends/Kconfig.ble
Normal file
34
subsys/logging/backends/Kconfig.ble
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) 2023 Victor Chavez
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config LOG_BACKEND_BLE
|
||||
bool "Bluetooth Low Energy (BLE) backend"
|
||||
depends on BT
|
||||
depends on LOG_PROCESS_THREAD_STACK_SIZE>=2048
|
||||
select LOG_OUTPUT
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
Backend that sends log messages over Bluetooth LE Notifications. This
|
||||
characteristic and its service are compatible with the Nordic UART
|
||||
Service (NUS), from the nRF Connect SDK.
|
||||
This allows to use this BLE Logger directly with a compatible app such
|
||||
as the nRF UART 2.0 or nRF Toolbox app.
|
||||
|
||||
if LOG_BACKEND_BLE
|
||||
|
||||
config LOG_BACKEND_BLE_BUF_SIZE
|
||||
int "BLE Logger Backend Buffer size"
|
||||
range 20 512
|
||||
default 20
|
||||
help
|
||||
Maximum buffer size that can be transmitted over the BLE Logger
|
||||
notification characteristic. The minimum size is 20 for the smallest
|
||||
MTU packet. Be sure to increase the MTU size in your application to use
|
||||
bigger values.
|
||||
Both BT_L2CAP_TX_MTU and BT_BUF_ACL_RX_SIZE will need to be increased.
|
||||
|
||||
backend = BLE
|
||||
backend-str = ble
|
||||
source "subsys/logging/Kconfig.template.log_format_config"
|
||||
|
||||
endif # LOG_BACKEND_BLE
|
||||
148
subsys/logging/backends/log_backend_ble.c
Normal file
148
subsys/logging/backends/log_backend_ble.c
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Victor Chavez
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/logging/log_backend.h>
|
||||
#include <zephyr/logging/log_output.h>
|
||||
#include <zephyr/logging/log_backend_ble.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
static uint8_t output_buf[CONFIG_LOG_BACKEND_BLE_BUF_SIZE];
|
||||
static bool panic_mode;
|
||||
static uint32_t log_format_current = CONFIG_LOG_BACKEND_BLE_OUTPUT_DEFAULT;
|
||||
static logger_backend_ble_hook user_hook;
|
||||
static void *user_ctx;
|
||||
/* Forward declarations*/
|
||||
const struct log_backend *log_backend_ble_get(void);
|
||||
|
||||
/**
|
||||
* @brief Callback for the subscription to the ble logger notification characteristic
|
||||
* @details This callback enables/disables automatically the logger when the notification
|
||||
* is subscribed.
|
||||
* @param attr The attribute that's changed value
|
||||
* @param value New value
|
||||
*/
|
||||
static void log_notify_changed(const struct bt_gatt_attr *attr, uint16_t value);
|
||||
|
||||
/** BLE Logger based on the UUIDs for the NRF Connect SDK NUS service
|
||||
* https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.3.0/nrf/libraries/bluetooth_services/services/nus.html
|
||||
*/
|
||||
#define NUS_SERVICE_UUID \
|
||||
BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x6E400001, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E))
|
||||
|
||||
#define LOGGER_TX_SERVICE_UUID \
|
||||
BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x6E400003, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E))
|
||||
|
||||
#define LOGGER_RX_SERVICE_UUID \
|
||||
BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x6E400002, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E))
|
||||
|
||||
/**
|
||||
* @brief BLE Service that represents this backend
|
||||
* @note Only transmission characteristic is used. The RX characteristic
|
||||
* is added to make the backend usable with the NRF toolbox app
|
||||
* which expects both characteristics.
|
||||
*/
|
||||
BT_GATT_SERVICE_DEFINE(ble_log_svc, BT_GATT_PRIMARY_SERVICE(NUS_SERVICE_UUID),
|
||||
BT_GATT_CHARACTERISTIC(LOGGER_TX_SERVICE_UUID, BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_READ, NULL, NULL, NULL),
|
||||
BT_GATT_CCC(log_notify_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
|
||||
BT_GATT_CHARACTERISTIC(LOGGER_RX_SERVICE_UUID, BT_GATT_CHRC_WRITE, 0,
|
||||
NULL, NULL, NULL),
|
||||
|
||||
);
|
||||
|
||||
/* Log characteristic attribute is defined after the first attribute (i.e. the service) */
|
||||
const struct bt_gatt_attr *log_characteristic = &ble_log_svc.attrs[1];
|
||||
|
||||
void logger_backend_ble_set_hook(logger_backend_ble_hook hook, void *ctx)
|
||||
{
|
||||
user_hook = hook;
|
||||
user_ctx = ctx;
|
||||
}
|
||||
|
||||
void log_notify_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||||
{
|
||||
ARG_UNUSED(attr);
|
||||
|
||||
const bool notify_enabled = value == BT_GATT_CCC_NOTIFY;
|
||||
|
||||
if (notify_enabled) {
|
||||
log_backend_activate(log_backend_ble_get(), NULL);
|
||||
} else {
|
||||
log_backend_deactivate(log_backend_ble_get());
|
||||
}
|
||||
if (user_hook != NULL) {
|
||||
user_hook(notify_enabled, user_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int line_out(uint8_t *data, size_t length, void *output_ctx)
|
||||
{
|
||||
const int notify_res = bt_gatt_notify(NULL, log_characteristic, data, length);
|
||||
|
||||
if (notify_res == 0) {
|
||||
return length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_OUTPUT_DEFINE(log_output_ble, line_out, output_buf, sizeof(output_buf));
|
||||
|
||||
static void process(const struct log_backend *const backend, union log_msg_generic *msg)
|
||||
{
|
||||
uint32_t flags = LOG_OUTPUT_FLAG_FORMAT_SYSLOG | LOG_OUTPUT_FLAG_TIMESTAMP;
|
||||
|
||||
if (panic_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
|
||||
|
||||
log_output_func(&log_output_ble, &msg->log, flags);
|
||||
}
|
||||
|
||||
static int format_set(const struct log_backend *const backend, uint32_t log_type)
|
||||
{
|
||||
log_format_current = log_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_ble(struct log_backend const *const backend)
|
||||
{
|
||||
log_backend_deactivate(log_backend_ble_get());
|
||||
}
|
||||
|
||||
static void panic(struct log_backend const *const backend)
|
||||
{
|
||||
panic_mode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Backend ready function for ble logger
|
||||
* @details After initialization of the logger, this function avoids
|
||||
* the logger subys to enable it. The logger is enabled automatically
|
||||
* via the notification changed callback.
|
||||
* @param backend Logger backend
|
||||
* @return Zephyr permission denied
|
||||
*/
|
||||
static int backend_ready(const struct log_backend *const backend)
|
||||
{
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
const struct log_backend_api log_backend_ble_api = {.process = process,
|
||||
.dropped = NULL,
|
||||
.panic = panic,
|
||||
.init = init_ble,
|
||||
.is_ready = backend_ready,
|
||||
.format_set = format_set,
|
||||
.notify = NULL};
|
||||
|
||||
LOG_BACKEND_DEFINE(log_backend_ble, log_backend_ble_api, true);
|
||||
|
||||
const struct log_backend *log_backend_ble_get(void)
|
||||
{
|
||||
return &log_backend_ble;
|
||||
}
|
||||
Loading…
Reference in a new issue