feat(ble_log): switch to the unified transport pool

Replace the legacy multi-LBM transport layer with one shared pool:

- one bitmap-indexed pool of CONFIG_BLE_LOG_POOL_TRANS_CNT transports
  with a non-yield reserve for ISR and critical-section writers;
- per-transport state machine (FREE/OPEN/CLAIMED/SENDING) guarded by a
  per-transport CAS lock; bitmaps are only candidate hints;
- claim/commit interface for the compressed-log path; claim bookkeeping
  lives in the pool (ble_log_pool_claim_t), not in the peripheral
  transport;
- dedicated Internal Snapshot transport and fixed-layout snapshot
  record (reason flags, version block, lc/esp/os clock samples, pool
  state, compact core statistics);
- source-local 24-bit wire sequences and compact per-source counters;
- UART console redirection stream writer (ble_log_redir_t);
- CMakeLists compiles ble_log_lbm_v2.c instead of ble_log_lbm.c; the
  legacy ble_log_lbm.c/.h stay in-tree, out of the build, until their
  removal;
- the public ble_log_src_t ABI is restored and frozen; protocol v7
  wire source IDs are a separate internal enum (ble_log_wire_src_t)
  and the older BLE Stack sources map onto the v7 core sources
  (LL_TASK/LL_ISR -> LL, LL_HCI/HCI -> HCI, HOST -> CUSTOM);
  BLE_LOG_VERSION 7;
- Kconfig: pool sizing options replace the LBM options, whose names
  remain as hidden deprecated symbols for backward sdkconfig
  compatibility; BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED becomes the single
  BLE_LOG_HCI_LOG_ENABLED switch for host and controller HCI traffic
  (Bluedroid and NimBLE host call sites follow the rename), enabled
  by default on all targets instead of only where
  BLE_LOG_IS_ESP_LEGACY_CONTROLLER; the old name keeps a deprecated
  promptless shim that selects the new symbol, so sdkconfig files
  still pinning it keep host HCI logging enabled;
- util: ble_log_cas_acquire/release become macros; multi-call-site
  pool helpers are no longer inline (IRAM);
- test app record structs gain a source_meta field for the v7 wire
  source byte;
- the Internal Snapshot no longer carries a schema_version: the record
  is self-identifying via int_src_code and the version block.
This commit is contained in:
Zhou Xiao
2026-09-10 15:39:55 +08:00
committed by guozifan
parent a1cbd92328
commit e801a4d509
22 changed files with 1786 additions and 244 deletions
+1 -1
View File
@@ -170,7 +170,7 @@ list(APPEND bt_common_priv_include_dirs
if(CONFIG_BLE_LOG_ENABLED)
list(APPEND bt_common_srcs
"${CMAKE_CURRENT_LIST_DIR}/ble_log/src/ble_log.c"
"${CMAKE_CURRENT_LIST_DIR}/ble_log/src/ble_log_lbm.c"
"${CMAKE_CURRENT_LIST_DIR}/ble_log/src/ble_log_lbm_v2.c"
"${CMAKE_CURRENT_LIST_DIR}/ble_log/src/ble_log_rt.c"
"${CMAKE_CURRENT_LIST_DIR}/ble_log/src/ble_log_util.c"
)
+74 -82
View File
@@ -1,55 +1,39 @@
config BLE_LOG_ENABLED
bool "Enable BT Log Async Output (Dev Only)"
select BLE_COMPRESSED_LOG_ENABLE
select BLE_HOST_COMPRESSED_LOG_ENABLE if BT_BLUEDROID_ENABLED
select BLE_HOST_COMPRESSED_LOG_ENABLE if BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED
select ESP_TIMER_IN_IRAM
default n
help
Enable BT Log Async Output
if BLE_LOG_ENABLED
config BLE_LOG_LBM_AUTO_FLUSH
bool "Enable automatic BLE Log LBM buffer flush"
default n
config BLE_LOG_POOL_TRANS_CNT
int "Number of transport buffers in the unified pool"
range 2 32
default 8
help
Periodically flush partially-filled BLE Log LBM transport buffers
that remain pending, reducing latency for low-volume or
intermittent logging.
Total number of transports shared by ordinary, Link Layer, ISR,
and critical-section log writers. Availability is represented by
32-bit bitmaps, so the maximum is 32.
config BLE_LOG_LBM_TRANS_BUF_SIZE
int "Total buffer memory per common LBM (bytes)"
default 2048
help
Total buffer memory allocated for each common pool log buffer
manager (LBM). This memory is divided equally among internal
transport buffers. Must be a multiple of BLE_LOG_TRANS_BUF_CNT
(currently 4).
The common pool contains:
- BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT atomic LBMs (task context)
- BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT atomic LBMs (ISR context)
- 2 spinlock-protected LBMs (one for task, one for ISR fallback)
Total common pool memory:
(ATOMIC_TASK_CNT + ATOMIC_ISR_CNT + 2) * BLE_LOG_LBM_TRANS_BUF_SIZE
config BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT
int "Count of log buffer managers with atomic lock protection for task context"
default 2
help
BLE Log module will search for an LBM with atomic lock protection first; if
all LBMs with atomic lock protection are unavailable, BLE Log module will
try to use the LBM with spin lock protection. So the more LBMs with atomic
lock protection are created, the better the logging performance will be.
config BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT
int "Count of log buffer managers with atomic lock protection for ISR context"
config BLE_LOG_POOL_NON_YIELD_RESERVE_CNT
int "Transport buffers reserved for non-yieldable contexts"
range 1 31
default 1
help
BLE Log module will search for an LBM with atomic lock protection first; if
all LBMs with atomic lock protection are unavailable, BLE Log module will
try to use the LBM with spin lock protection. So the more LBMs with atomic
lock protection are created, the more ISRs can nest.
Buffers that ordinary task writers cannot consume. ISR and
critical-section writers try the shared region first, then this
reserve. The value must remain below BLE_LOG_POOL_TRANS_CNT.
config BLE_LOG_POOL_TRANS_SIZE
int "Per-transport buffer size (bytes)"
range 640 10240
default 640
help
Size of every unified-pool transport. One complete frame must fit
in one transport. SPI builds require a multiple of four so they
can append peripheral-only zero padding to each logical frame.
config BLE_LOG_IS_ESP_CONTROLLER
bool "Current BLE Controller is ESP BLE Controller"
@@ -77,44 +61,9 @@ if BLE_LOG_ENABLED
help
Enable BLE Log for Link Layer
if BLE_LOG_LL_ENABLED
config BLE_LOG_LBM_LL_TRANS_BUF_SIZE
int "Total buffer memory per Link Layer LBM (bytes)"
default 2048
help
Total buffer memory allocated for each Link Layer dedicated
log buffer manager (LBM). This memory is divided equally among
internal transport buffers. Must be a multiple of
BLE_LOG_TRANS_BUF_CNT (currently 4).
There are 2 Link Layer LBMs without lock protection (each is
accessed from a single context only):
- LL task LBM (Link Layer task context logs)
- LL HCI LBM (Link Layer HCI context logs)
Total LL pool memory: 2 * BLE_LOG_LBM_LL_TRANS_BUF_SIZE
config BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT_ENABLED
bool "Enable LL HCI Log Payload Length Limit"
default n
help
Enable length limit for LL HCI Log payload (addr_append).
When enabled, if len_append exceeds the configured limit,
it will be truncated to the maximum length.
config BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT
int "LL HCI Log Payload Length Limit (bytes)"
depends on BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT_ENABLED
default 32
help
Maximum length for LL HCI Log payload (len_append).
When the feature is enabled and len_append exceeds this value,
it will be truncated.
endif
config BLE_LOG_HOST_LOG
bool "Enable BLE Log for Host"
depends on BT_BLUEDROID_ENABLED
depends on BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED
default y
help
Enable BLE Log for the Host stack (Bluedroid or NimBLE).
@@ -124,13 +73,24 @@ if BLE_LOG_ENABLED
the standard UART logging path. Disable this option to keep
BLE Log enabled for the controller/link layer only.
config BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
bool "Enable BLE Host side HCI Logging"
default y if BLE_LOG_IS_ESP_LEGACY_CONTROLLER
config BLE_LOG_HCI_LOG_ENABLED
bool "Enable BLE HCI Logging"
default y
help
Enable HCI packet logging captured on the Host side
(Bluedroid / NimBLE HCI HAL). Useful for correlating
host events with controller-side HCI traces.
(Bluedroid / NimBLE HCI HAL). This is the single HCI
logging switch for both Host and Controller traffic:
the controller no longer maintains its own internal
LL HCI log, and controller-side HCI records are not
emitted separately.
config BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
bool "Enable BLE Host side HCI Logging"
default n
select BLE_LOG_HCI_LOG_ENABLED
help
Deprecated. Renamed to BLE_LOG_HCI_LOG_ENABLED; kept so sdkconfig
files pinning the old name keep Host side HCI logging enabled.
config BLE_LOG_TS_ENABLED
bool "Enable BLE Log Timestamp Synchronization (TS)"
@@ -165,8 +125,11 @@ if BLE_LOG_ENABLED
bool "Test only transport"
help
Test transport that models DMA ownership and optional
link-rate backpressure. Selected by BLE Log test apps
only; not shown in menuconfig.
link-rate backpressure. Intended for the BLE Log test apps
only: outside them nothing drains the transmitted buffers,
so selecting this transport in a production build stalls
log output. The BLE Log test apps select it through their
sdkconfig.defaults.
config BLE_LOG_PRPH_SPI_MASTER_DMA
bool "Utilize SPI master DMA driver as transport"
@@ -240,6 +203,35 @@ if BLE_LOG_ENABLED
int
default 512
config BLE_LOG_LBM_TRANS_BUF_SIZE
int
default 2048
config BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT
int
default 2
config BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT
int
default 1
config BLE_LOG_LBM_LL_TRANS_BUF_SIZE
int
default 2048
config BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT_ENABLED
bool
default n
config BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT
int
depends on BLE_LOG_LL_HCI_LOG_PAYLOAD_LEN_LIMIT_ENABLED
default 32
config BLE_LOG_LBM_AUTO_FLUSH
bool
default n
config BLE_LOG_ENH_STAT_ENABLED
bool
default y
@@ -20,6 +20,8 @@
* The number of BLE Log source code will directly determine the number of statistic manager
* memory requirements, keep it as less as possible; it's recommended to use subcode for more
* log data structure decoding */
/* CRITICAL: this enum is a public ABI and must not be reordered or renamed.
* Its values are also the on-wire source IDs of protocol v7 frames. */
typedef enum {
/* Internal */
BLE_LOG_SRC_INTERNAL = 0,
@@ -65,6 +67,8 @@ bool ble_log_enable(bool enable);
/* Blocking; call only from a caller-owned task, not an ISR or system callback. */
void ble_log_flush(void);
bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len);
uint8_t *ble_log_claim(ble_log_src_t src_code, size_t max_len, uint32_t *handle);
void ble_log_commit(uint32_t handle, size_t actual_len);
void ble_log_dump_to_console(void);
#if CONFIG_BLE_LOG_LL_ENABLED
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
+12 -18
View File
@@ -10,7 +10,7 @@
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_rt.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "ble_log_prph.h"
#include "ble_log_util.h"
#include "esp_log.h"
@@ -45,24 +45,24 @@ bool ble_log_init(void)
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
/* Initialize BLE Log Runtime */
if (!ble_log_rt_init()) {
goto exit;
}
/* Initialize BLE Log LBM */
/* Allocate pool and dedicated Internal transport before runtime starts. */
if (!ble_log_lbm_init()) {
goto exit;
}
/* Initialize BLE Log peripheral interface */
if (!ble_log_prph_init(BLE_LOG_TRANS_TOTAL_CNT)) {
goto exit;
}
/* Initialization done */
if (!ble_log_rt_init()) {
goto exit;
}
ble_log_inited = true;
ble_log_enable(true);
if (!ble_log_enable(true) ||
!ble_log_internal_snapshot(BLE_LOG_SNAPSHOT_REASON_INIT, NULL, true)) {
goto exit;
}
esp_err_t ret = esp_register_shutdown_handler(ble_log_shutdown_handler);
if (ret == ESP_OK) {
shutdown_handler_registered = true;
@@ -70,12 +70,6 @@ bool ble_log_init(void)
ESP_LOGW(TAG, "Register shutdown handler failed, ret = 0x%x", ret);
}
/* Write initialization done log */
ble_log_info_t ble_log_info = {
.int_src_code = BLE_LOG_INT_SRC_INIT_DONE,
.version = BLE_LOG_VERSION,
};
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
return true;
exit:
@@ -94,9 +88,9 @@ void ble_log_deinit(void)
}
}
ble_log_inited = false;
ble_log_lbm_close();
ble_log_lbm_begin_deinit();
/* CRITICAL — Deinit ordering rationale:
/* CRITICAL - Deinit ordering rationale:
*
* 1. The LBM writer gate is closed before submodule teardown. Writers
* already inside the gate keep a reference until they finish; later
File diff suppressed because it is too large Load Diff
+57 -46
View File
@@ -11,7 +11,7 @@
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_rt.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "esp_log.h"
#include "esp_timer.h"
@@ -55,6 +55,7 @@ BLE_LOG_STATIC BLE_LOG_DRAM_ATTR volatile uint32_t rt_ref_count = 0;
BLE_LOG_STATIC BLE_LOG_DRAM_ATTR QueueHandle_t rt_queue_handle = NULL;
BLE_LOG_STATIC BLE_LOG_DRAM_ATTR esp_timer_handle_t rt_defer_timer = NULL;
BLE_LOG_STATIC uint32_t rt_last_hook_os_ts = 0;
BLE_LOG_STATIC ble_log_version_info_t rt_version_info;
#if CONFIG_BLE_LOG_TS_ENABLED
BLE_LOG_STATIC BLE_LOG_DRAM_ATTR uint32_t rt_ts_enabled = 0;
BLE_LOG_STATIC esp_timer_handle_t rt_ts_timer = NULL;
@@ -63,6 +64,7 @@ BLE_LOG_STATIC esp_timer_handle_t rt_ts_timer = NULL;
/* PRIVATE FUNCTION DECLARATION */
BLE_LOG_STATIC void ble_log_rt_defer_cb(void *arg);
BLE_LOG_STATIC bool ble_log_rt_dispatch(QueueHandle_t queue, UBaseType_t pending);
BLE_LOG_STATIC void ble_log_rt_version_info_init(void);
BLE_LOG_STATIC void ble_log_rt_run_hook(void);
#if CONFIG_BLE_LOG_TS_ENABLED
BLE_LOG_STATIC void ble_log_rt_ts_trigger(void *arg);
@@ -75,53 +77,58 @@ BLE_LOG_STATIC void ble_log_commit_copy(uint8_t *dst, const char *src, size_t le
BLE_LOG_MEMCPY(dst, src, strnlen(src, len));
}
BLE_LOG_STATIC void ble_log_rt_version_info_init(void)
{
BLE_LOG_MEMSET(&rt_version_info, 0, sizeof(rt_version_info));
rt_version_info.int_src_code = BLE_LOG_INT_SRC_VERSION_INFO;
rt_version_info.version = BLE_LOG_VERSION;
#ifdef BLE_LOG_IDF_COMMIT
BLE_LOG_MEMCPY(rt_version_info.idf_commit, BLE_LOG_IDF_COMMIT,
BLE_LOG_IDF_COMMIT_LEN);
#endif
#if CONFIG_BT_CONTROLLER_ENABLED && defined(BLE_LOG_CONTROLLER_GET_COMMIT)
ble_log_commit_copy(rt_version_info.controller_commit,
BLE_LOG_CONTROLLER_GET_COMMIT(), BLE_LOG_LIB_COMMIT_LEN);
#endif
#if CONFIG_BT_CONTROLLER_ENABLED && defined(BLE_LOG_BTDM_COMMON_GET_COMMIT)
ble_log_commit_copy(rt_version_info.btdm_common_commit,
BLE_LOG_BTDM_COMMON_GET_COMMIT(), BLE_LOG_LIB_COMMIT_LEN);
#endif
#if CONFIG_BLE_MESH && CONFIG_BLE_MESH_V11_SUPPORT
const char *mesh_commit = strrchr(bt_mesh_v11_commit_str, ' ');
if (mesh_commit) {
ble_log_commit_copy(rt_version_info.mesh_commit, mesh_commit + 1,
BLE_LOG_LIB_COMMIT_LEN);
}
#endif
#if CONFIG_BT_AUDIO && CONFIG_SOC_BLE_AUDIO_SUPPORTED
ble_log_commit_copy(rt_version_info.audio_commit, lib_audio_commit_get(),
BLE_LOG_LIB_COMMIT_LEN);
#endif
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
rt_version_info.chip_model = (uint16_t)chip_info.model;
rt_version_info.chip_revision = chip_info.revision;
ble_log_internal_set_version_info(&rt_version_info);
}
BLE_LOG_STATIC void ble_log_rt_run_hook(void)
{
if (!ble_log_lbm_is_enabled()) {
return;
}
#if CONFIG_BLE_LOG_TS_ENABLED
if (BLE_LOG_ATOMIC_LOAD_ACQUIRE(rt_ts_enabled)) {
return;
}
#endif
uint32_t now = pdTICKS_TO_MS(xTaskGetTickCount());
if ((uint32_t)(now - rt_last_hook_os_ts) < BLE_LOG_TS_TRIGGER_TIMEOUT_MS) {
return;
}
rt_last_hook_os_ts = now;
/* Write version info: BLE Log version, idf commit (build-time),
* linked-in BLE lib commits, chip model/revision (efuse, runtime-only).
* Libs absent from the build leave their fields zero. */
ble_log_version_info_t version_info = {
.int_src_code = BLE_LOG_INT_SRC_VERSION_INFO,
.version = BLE_LOG_VERSION,
};
#ifdef BLE_LOG_IDF_COMMIT
BLE_LOG_MEMCPY(version_info.idf_commit, BLE_LOG_IDF_COMMIT, BLE_LOG_IDF_COMMIT_LEN);
#endif
#if CONFIG_BT_CONTROLLER_ENABLED && defined(BLE_LOG_CONTROLLER_GET_COMMIT)
ble_log_commit_copy(version_info.controller_commit, BLE_LOG_CONTROLLER_GET_COMMIT(),
BLE_LOG_LIB_COMMIT_LEN);
#endif
#if CONFIG_BT_CONTROLLER_ENABLED && defined(BLE_LOG_BTDM_COMMON_GET_COMMIT)
ble_log_commit_copy(version_info.btdm_common_commit, BLE_LOG_BTDM_COMMON_GET_COMMIT(),
BLE_LOG_LIB_COMMIT_LEN);
#endif
#if CONFIG_BLE_MESH && CONFIG_BLE_MESH_V11_SUPPORT
/* The hash is the substring after the last space of the lib string */
const char *mesh_commit = strrchr(bt_mesh_v11_commit_str, ' ');
if (mesh_commit) {
ble_log_commit_copy(version_info.mesh_commit, mesh_commit + 1,
BLE_LOG_LIB_COMMIT_LEN);
}
#endif
#if CONFIG_BT_AUDIO && CONFIG_SOC_BLE_AUDIO_SUPPORTED
ble_log_commit_copy(version_info.audio_commit, lib_audio_commit_get(),
BLE_LOG_LIB_COMMIT_LEN);
#endif
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
version_info.chip_model = (uint16_t)chip_info.model;
version_info.chip_revision = chip_info.revision;
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&version_info,
sizeof(version_info));
ble_log_write_enh_stat();
ble_log_write_buf_util();
(void)ble_log_internal_snapshot(BLE_LOG_SNAPSHOT_REASON_PERIODIC,
NULL, false);
}
BLE_LOG_STATIC bool ble_log_rt_dispatch(QueueHandle_t queue, UBaseType_t pending)
@@ -170,10 +177,12 @@ BLE_LOG_STATIC void ble_log_rt_ts_trigger(void *arg)
return;
}
ble_log_ts_info_t *ts_info = NULL;
ble_log_ts_info_update(&ts_info);
if (ts_info) {
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)ts_info, sizeof(ble_log_ts_info_t));
ble_log_ts_info_t ts_info;
if (ble_log_ts_info_update(&ts_info)) {
(void)ble_log_internal_snapshot(
BLE_LOG_SNAPSHOT_REASON_PERIODIC |
BLE_LOG_SNAPSHOT_REASON_TS_VALID,
&ts_info, false);
}
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
@@ -185,6 +194,7 @@ bool ble_log_rt_init(void)
return true;
}
ble_log_rt_version_info_init();
rt_queue_handle = xQueueCreate(BLE_LOG_TRANS_TOTAL_CNT, sizeof(ble_log_prph_trans_t *));
if (!rt_queue_handle) {
goto exit;
@@ -314,11 +324,12 @@ BLE_LOG_IRAM_ATTR void ble_log_rt_submit_trans(ble_log_prph_trans_t *trans)
#if CONFIG_BLE_LOG_TS_ENABLED
bool ble_log_sync_enable(bool enable)
{
if (!BLE_LOG_ATOMIC_LOAD_ACQUIRE(rt_inited)) {
if (!ble_log_ref_count_try_acquire(&rt_ref_count, &rt_inited)) {
return false;
}
BLE_LOG_ATOMIC_STORE_RELEASE(rt_ts_enabled, enable);
ble_log_ts_reset(enable);
BLE_LOG_REF_COUNT_RELEASE(&rt_ref_count);
return true;
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
@@ -84,9 +84,11 @@ void ble_log_ts_reset(bool status)
return;
}
BLE_LOG_ENTER_CRITICAL();
if (!status && !ts_info->io_level) {
gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, 1);
}
ts_info->io_level = 0;
gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, 0);
BLE_LOG_EXIT_CRITICAL();
}
@@ -74,12 +74,12 @@ uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len)
BLE_LOG_IRAM_ATTR
bool ble_log_ref_count_try_acquire(volatile uint32_t *ref_count,
const uint32_t *inited)
const uint32_t *gate)
{
/* The seq_cst increment/check pairs with deinit's seq_cst gate close
* before it waits for the reference count. */
/* The seq_cst increment/check pairs with a seq_cst gate close before the
* owner waits for the reference count. */
BLE_LOG_REF_COUNT_ACQUIRE_SEQ_CST(ref_count);
if (BLE_LOG_ATOMIC_LOAD_SEQ_CST(*inited)) {
if (BLE_LOG_ATOMIC_LOAD_SEQ_CST(*gate)) {
return true;
}
BLE_LOG_REF_COUNT_RELEASE(ref_count);
@@ -0,0 +1,240 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_LBM_V2_H__
#define __BLE_LOG_LBM_V2_H__
/* -------------------------------------------------- */
/* BLE Log - Unified Transport Pool (v7) */
/* -------------------------------------------------- */
/* Replaces the legacy multi-LBM design (ble_log_lbm.h) with one shared
* transport pool. Written as a new module so the legacy implementation
* stays untouched and reviewable as a pure addition. */
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_prph.h"
#include "ble_log_ts.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
/* ------------------------- */
/* Log Frame Defines */
/* ------------------------- */
typedef struct {
uint16_t length;
uint32_t frame_meta;
} __attribute__((packed)) ble_log_frame_head_t;
#define BLE_LOG_FRAME_HEAD_LEN (sizeof(ble_log_frame_head_t))
#define BLE_LOG_FRAME_TAIL_LEN (sizeof(uint32_t))
#define BLE_LOG_FRAME_OVERHEAD (BLE_LOG_FRAME_HEAD_LEN + BLE_LOG_FRAME_TAIL_LEN)
#define BLE_LOG_MAKE_SOURCE_META(src, non_yield) \
(((src) & BLE_LOG_SRC_ID_MASK) | ((non_yield) ? BLE_LOG_SRC_FLAG_NON_YIELD : 0))
#define BLE_LOG_MAKE_FRAME_META(source_meta, sn) \
(((source_meta) & 0xffU) | (((sn) & 0x00ffffffU) << 8))
/* ------------------------------------- */
/* Unified Buffer Pool Defines */
/* ------------------------------------- */
#define BLE_LOG_POOL_TRANS_CNT CONFIG_BLE_LOG_POOL_TRANS_CNT
#define BLE_LOG_POOL_NON_YIELD_RESERVE_CNT CONFIG_BLE_LOG_POOL_NON_YIELD_RESERVE_CNT
#define BLE_LOG_POOL_SHARED_CNT (BLE_LOG_POOL_TRANS_CNT - BLE_LOG_POOL_NON_YIELD_RESERVE_CNT)
#define BLE_LOG_POOL_TRANS_SIZE CONFIG_BLE_LOG_POOL_TRANS_SIZE
#define BLE_LOG_TRANS_SIZE BLE_LOG_POOL_TRANS_SIZE
#define BLE_LOG_MAX_PAYLOAD_LEN (BLE_LOG_POOL_TRANS_SIZE - BLE_LOG_FRAME_OVERHEAD)
#define BLE_LOG_TRANS_INTERNAL_CNT (1)
#if BLE_LOG_UART_REDIR_ENABLED
#define BLE_LOG_TRANS_REDIR_CNT BLE_LOG_TRANS_BUF_CNT
#else
#define BLE_LOG_TRANS_REDIR_CNT (0)
#endif
#define BLE_LOG_TRANS_TOTAL_CNT \
(BLE_LOG_POOL_TRANS_CNT + BLE_LOG_TRANS_INTERNAL_CNT + BLE_LOG_TRANS_REDIR_CNT)
/* --------------------------------------- */
/* Protocol v7 Source ID Space */
/* --------------------------------------- */
/* The frozen public ble_log_src_t values are the on-wire and statistic
* source IDs: the frame source byte carries the enum value directly and
* every source keeps its own wire sequence, matching the legacy wire
* identity so existing decoders keep working. */
#define BLE_LOG_SRC_ID_MASK 0x7f
#define BLE_LOG_SRC_FLAG_NON_YIELD 0x80
#define BLE_LOG_SRC_ID(source_meta) ((source_meta) & BLE_LOG_SRC_ID_MASK)
#define BLE_LOG_SRC_IS_NON_YIELD(source_meta) (((source_meta) & BLE_LOG_SRC_FLAG_NON_YIELD) != 0)
/* Statistic slots in the Internal Snapshot: every public source that can
* produce frames, i.e. CUSTOM through ENCODE. INTERNAL frames carry their
* own snapshot sequence in the frame header; REDIR is a raw console
* stream. */
#define BLE_LOG_SRC_CORE_FIRST BLE_LOG_SRC_CUSTOM
#define BLE_LOG_SRC_CORE_COUNT (BLE_LOG_SRC_ENCODE - BLE_LOG_SRC_CORE_FIRST + 1)
/* ------------------------------------- */
/* UART Redirection Manager */
/* ------------------------------------- */
#if BLE_LOG_UART_REDIR_ENABLED
typedef struct {
ble_log_prph_trans_t *trans[BLE_LOG_TRANS_BUF_CNT];
SemaphoreHandle_t mutex;
int trans_idx;
volatile uint32_t inflight;
volatile uint32_t inflight_peak;
} ble_log_redir_t;
#endif
/* -------------------------------- */
/* Compact Core Statistics */
/* -------------------------------- */
typedef struct {
uint32_t written_frame_cnt;
uint32_t lost_frame_cnt;
} __attribute__((packed)) ble_log_source_stat_t;
/* Runtime per-source counters. The aligned wrapper keeps the embedded
* packed counters word-aligned, so atomic updates stay single-instruction
* (amo/s32c1i) on both toolchains. */
typedef struct {
ble_log_source_stat_t counters;
} __attribute__((aligned(4))) ble_log_stat_mgr_t;
#define BLE_LOG_GET_FRAME_SN(VAR) BLE_LOG_ATOMIC_ADD_RELAXED(VAR, 1)
/* One 24-bit Global SN is shared by every non-INTERNAL source: consumed at
* API entry (before pool contention), it orders all log attempts —
* including equal-timestamp records from different sources — and every
* lost or rejected attempt leaves a gap. Internal Snapshot frames keep
* their own separate sequence: a skipped periodic snapshot burns one
* snapshot SN, so a gap there counts lost snapshots without a dedicated
* field. Neither sequence is ever reset. */
#define BLE_LOG_SN_MODULO 0x00ffffffU
#define BLE_LOG_GET_GLOBAL_SN() \
((uint32_t)BLE_LOG_GET_FRAME_SN(g_frame_sn) & BLE_LOG_SN_MODULO)
#define BLE_LOG_GET_SNAPSHOT_SN() \
((uint32_t)BLE_LOG_GET_FRAME_SN(g_snapshot_sn) & BLE_LOG_SN_MODULO)
/* -------------------------------- */
/* Internal Snapshot Frame */
/* -------------------------------- */
#define BLE_LOG_SNAPSHOT_REASON_INIT BIT(0)
#define BLE_LOG_SNAPSHOT_REASON_PERIODIC BIT(1)
#define BLE_LOG_SNAPSHOT_REASON_FLUSH BIT(2)
#define BLE_LOG_SNAPSHOT_REASON_TS_VALID BIT(3)
typedef struct {
uint8_t int_src_code;
uint16_t reason_flags;
ble_log_version_info_t version_info;
/* Clock samples captured at the same instant, mirroring
* ble_log_ts_info_t (minus its int_src_code). */
struct {
uint8_t io_level;
uint32_t lc_ts; /* Link-layer clock; 0 when not available */
uint32_t esp_ts; /* esp_timer_get_time() */
uint32_t os_ts; /* FreeRTOS tick count in ms */
} __attribute__((packed)) ts;
/* Unified pool state at capture time. */
struct {
uint8_t trans_cnt;
uint8_t non_yield_reserve_cnt;
uint8_t inflight;
uint8_t inflight_peak;
} __attribute__((packed)) pool;
ble_log_source_stat_t stats[BLE_LOG_SRC_CORE_COUNT];
} __attribute__((packed)) ble_log_internal_snapshot_t;
#define BLE_LOG_INTERNAL_FRAME_LEN \
(BLE_LOG_FRAME_OVERHEAD + sizeof(uint32_t) + sizeof(ble_log_internal_snapshot_t))
#define BLE_LOG_INTERNAL_TRANS_SIZE \
((BLE_LOG_INTERNAL_FRAME_LEN + 3U) & ~3U)
/* -------------------------- */
/* Link Layer Defines */
/* -------------------------- */
#if CONFIG_BLE_LOG_LL_ENABLED
/* Numeric positions are an ABI with prebuilt controller libraries. */
enum {
BLE_LOG_LL_FLAG_CONTINUE = 0,
BLE_LOG_LL_FLAG_END = 1,
BLE_LOG_LL_FLAG_TASK = 2,
BLE_LOG_LL_FLAG_ISR = 3,
BLE_LOG_LL_FLAG_HCI = 4,
BLE_LOG_LL_FLAG_RAW = 5,
BLE_LOG_LL_FLAG_OMDATA = 6,
BLE_LOG_LL_FLAG_HCI_UPSTREAM = 7,
};
#endif
/* ------------------------------- */
/* Compile-Time Guards */
/* ------------------------------- */
_Static_assert(sizeof(ble_log_frame_head_t) == 6,
"Unexpected BLE Log frame header size");
_Static_assert(BLE_LOG_POOL_TRANS_CNT >= 2 && BLE_LOG_POOL_TRANS_CNT <= 32,
"BLE_LOG_POOL_TRANS_CNT must be within [2, 32]");
_Static_assert(BLE_LOG_POOL_NON_YIELD_RESERVE_CNT > 0 &&
BLE_LOG_POOL_NON_YIELD_RESERVE_CNT < BLE_LOG_POOL_TRANS_CNT,
"Non-yield reserve must leave at least one shared transport");
_Static_assert(BLE_LOG_POOL_TRANS_SIZE >= BLE_LOG_FRAME_OVERHEAD + sizeof(uint32_t),
"BLE_LOG_POOL_TRANS_SIZE is too small for a timestamped frame");
_Static_assert(BLE_LOG_POOL_TRANS_SIZE <= UINT16_MAX,
"BLE_LOG_POOL_TRANS_SIZE exceeds the transport size field");
_Static_assert(BLE_LOG_POOL_TRANS_SIZE <= 10240,
"BLE_LOG_POOL_TRANS_SIZE exceeds the peripheral transfer limit");
#if CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA || CONFIG_BLE_LOG_PRPH_SPI_MASTER_HD
_Static_assert((BLE_LOG_POOL_TRANS_SIZE & 3U) == 0,
"SPI BLE Log transport size must be four-byte aligned");
#endif
_Static_assert(sizeof(ble_log_version_info_t) == 58,
"Unexpected BLE Log version information size");
_Static_assert(sizeof(ble_log_source_stat_t) == 8,
"Unexpected BLE Log source statistic size");
_Static_assert(offsetof(ble_log_stat_mgr_t, counters) == 0 &&
sizeof(ble_log_stat_mgr_t) == 8,
"stat manager layout must keep the counters word-aligned");
_Static_assert(sizeof(ble_log_internal_snapshot_t) == 134,
"Unexpected BLE Log Internal Snapshot size");
_Static_assert(BLE_LOG_INTERNAL_FRAME_LEN == 148,
"Unexpected BLE Log Internal frame size");
_Static_assert(BLE_LOG_INTERNAL_TRANS_SIZE >= BLE_LOG_INTERNAL_FRAME_LEN,
"Internal transport is too small");
_Static_assert((BLE_LOG_TRANS_BUF_CNT & (BLE_LOG_TRANS_BUF_CNT - 1)) == 0,
"BLE_LOG_TRANS_BUF_CNT must be a power of two");
/* --------------------------- */
/* Internal Interfaces */
/* --------------------------- */
bool ble_log_lbm_init(void);
void ble_log_lbm_begin_deinit(void);
void ble_log_lbm_deinit(void);
bool ble_log_lbm_is_enabled(void);
void ble_log_lbm_flush_open_transports(void);
void ble_log_lbm_recycle_trans(ble_log_prph_trans_t *trans);
void ble_log_internal_set_version_info(const ble_log_version_info_t *version_info);
bool ble_log_internal_snapshot(uint16_t reason_flags,
const ble_log_ts_info_t *ts_info,
bool required);
/* Claim/commit: the public ble_log_src_t is accepted for API stability, but
* only BLE_LOG_SRC_ENCODE is supported; its frames are stamped with the
* ENCODE source ID on the wire. */
uint8_t *ble_log_claim(ble_log_src_t src_code, size_t max_len, uint32_t *handle);
void ble_log_commit(uint32_t handle, size_t actual_len);
#if BLE_LOG_UART_REDIR_ENABLED
void ble_log_lbm_stream_write(ble_log_redir_t *redir, ble_log_src_t src_code,
uint32_t timestamp, const uint8_t *data, size_t len);
void ble_log_lbm_stream_flush(ble_log_redir_t *redir, ble_log_src_t src_code);
ble_log_redir_t *ble_log_prph_get_redir_lbm(void);
#endif
#endif /* __BLE_LOG_LBM_V2_H__ */
@@ -10,32 +10,57 @@
/* BLE Log - Peripheral Interface */
/* ------------------------------ */
/* INCLUDE */
#include "ble_log_util.h"
/* TYPEDEF */
#if defined(CONFIG_BLE_LOG_PRPH_UART_DMA) && (CONFIG_BLE_LOG_PRPH_UART_DMA_PORT == 0)
#define BLE_LOG_UART_REDIR_ENABLED (1)
#else
#define BLE_LOG_UART_REDIR_ENABLED (0)
#endif
typedef enum {
BLE_LOG_TRANS_STATE_FREE = 0,
BLE_LOG_TRANS_STATE_OPEN,
BLE_LOG_TRANS_STATE_CLAIMED,
BLE_LOG_TRANS_STATE_SENDING,
} ble_log_trans_state_t;
typedef enum {
BLE_LOG_TRANS_OWNER_POOL = 0,
BLE_LOG_TRANS_OWNER_INTERNAL,
BLE_LOG_TRANS_OWNER_REDIR,
} ble_log_trans_owner_t;
#define BLE_LOG_TRANS_ID_NONE (0xff)
typedef struct {
volatile uint32_t prph_owned;
/* Transport lifecycle ownership, shared with the runtime dispatch and
* the peripheral tx-done recycle. Claim/commit bookkeeping deliberately
* lives in the pool (ble_log_lbm_v2.c), not here. */
volatile ble_log_atomic_lock_t atomic_lock;
volatile uint8_t state;
uint8_t id;
uint8_t owner_kind;
uint8_t *buf;
uint16_t size;
uint16_t pos;
/* Peripheral implementation specific context */
/* Peripheral implementation specific context. */
void *ctx;
/* Opaque back-reference to owning LBM, set once at init */
void *owner;
} ble_log_prph_trans_t;
#define BLE_LOG_TRANS_FREE_SPACE(trans) ((trans)->size - (trans)->pos)
#define BLE_LOG_TRANS_BUF_CNT (4)
/* INTERFACE */
bool ble_log_prph_init(size_t trans_cnt);
void ble_log_prph_deinit(void);
bool ble_log_prph_trans_init(ble_log_prph_trans_t **trans, size_t trans_size);
void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans);
void ble_log_prph_send_trans(ble_log_prph_trans_t *trans);
#if BLE_LOG_UART_REDIR_ENABLED
bool ble_log_prph_flush(void);
void ble_log_prph_reset_util_counters(void);
#endif
#endif /* __BLE_LOG_PRPH_H__ */
@@ -27,9 +27,11 @@
#define BLE_LOG_ATOMIC_LOAD_RELAXED(VAR) __atomic_load_n(&(VAR), __ATOMIC_RELAXED)
#define BLE_LOG_ATOMIC_STORE_RELEASE(VAR, VALUE) __atomic_store_n(&(VAR), (VALUE), __ATOMIC_RELEASE)
#define BLE_LOG_ATOMIC_STORE_RELAXED(VAR, VALUE) __atomic_store_n(&(VAR), (VALUE), __ATOMIC_RELAXED)
#define BLE_LOG_ATOMIC_ADD_RELAXED(VAR, VALUE) __atomic_fetch_add(&(VAR), (VALUE), __ATOMIC_RELAXED)
typedef uint32_t ble_log_atomic_lock_t;
/* Reference counting macros */
#define BLE_LOG_REF_COUNT_ACQUIRE(VAR) __atomic_fetch_add(VAR, 1, __ATOMIC_ACQUIRE)
#define BLE_LOG_REF_COUNT_RELEASE(VAR) __atomic_fetch_sub(VAR, 1, __ATOMIC_RELEASE)
/* Closing gate: pairs an inited-flag store with a reference-count load (and
* vice versa) at seq_cst so deinit and a submitter cannot both observe the
@@ -76,22 +78,14 @@ extern void esp_panic_handler_feed_wdts(void);
#define BLE_LOG_FEED_WDT() esp_panic_handler_feed_wdts()
/* INLINE */
BLE_LOG_IRAM_ATTR static inline
bool ble_log_cas_acquire(volatile bool *cas_lock)
{
bool expected = false;
return __atomic_compare_exchange_n(
cas_lock, &expected, true, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED
);
}
/* Compare-and-swap lock as macros: single-instruction acquire/release used
* from several IRAM sites; a function would add an IRAM call site each. */
#define ble_log_cas_acquire(cas_lock) \
(__atomic_exchange_n((cas_lock), 1, __ATOMIC_ACQUIRE) == 0)
#define ble_log_cas_release(cas_lock) \
__atomic_store_n((cas_lock), 0, __ATOMIC_RELEASE)
BLE_LOG_IRAM_ATTR static inline
void ble_log_cas_release(volatile bool *cas_lock)
{
__atomic_store_n(cas_lock, false, __ATOMIC_RELEASE);
}
#define BLE_LOG_VERSION (6)
#define BLE_LOG_VERSION (7)
#define BLE_LOG_IDF_COMMIT_LEN (12)
/* Lib commit hashes are at most 10 hex chars; zero-padded when shorter */
#define BLE_LOG_LIB_COMMIT_LEN (10)
@@ -106,6 +100,7 @@ typedef enum {
BLE_LOG_INT_SRC_BUF_UTIL,
BLE_LOG_INT_SRC_FINAL_STAT,
BLE_LOG_INT_SRC_VERSION_INFO,
BLE_LOG_INT_SRC_SNAPSHOT,
BLE_LOG_INT_SRC_MAX,
} ble_log_int_src_t;
@@ -131,7 +126,7 @@ uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len);
/* Acquire a lifetime reference only while the closing gate remains open. */
bool ble_log_ref_count_try_acquire(volatile uint32_t *ref_count,
const uint32_t *inited);
const uint32_t *gate);
/* Task-context wait; returns false if the count stays above max for one second. */
bool ble_log_ref_count_wait(volatile uint32_t *ref_count, uint32_t max_ref_count);
@@ -9,7 +9,7 @@
/* INCLUDE */
#include "ble_log_prph_dummy.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
/* INTERFACE */
bool ble_log_prph_init(size_t trans_cnt)
@@ -82,8 +82,8 @@ void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans)
}
/* Dummy transport has no DMA/hardware -- recycle the buffer immediately
* so that ble_log_lbm_get_trans() can reuse it and ble_log_flush() does
* not hang waiting for prph_owned to clear. Real peripherals (UART DMA,
* so that the pool can reuse it and ble_log_flush() does not hang waiting
* for it to drain. Real peripherals (UART DMA,
* SPI DMA) do the same work inside their asynchronous tx_done callbacks. */
void ble_log_prph_send_trans(ble_log_prph_trans_t *trans)
{
@@ -10,7 +10,7 @@
/* INCLUDE */
#include "ble_log_prph_spi_master_dma.h"
#include "ble_log_prph_spi_common.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "esp_timer.h"
@@ -26,6 +26,7 @@
/* VARIABLE */
BLE_LOG_STATIC bool prph_inited = false;
BLE_LOG_STATIC bool bus_inited = false;
BLE_LOG_STATIC spi_device_handle_t dev_handle = NULL;
BLE_LOG_STATIC BLE_LOG_DRAM_ATTR uint32_t last_tx_done_ts = 0;
@@ -37,7 +38,7 @@ BLE_LOG_STATIC void spi_master_dma_pre_tx_cb(spi_transaction_t *spi_trans);
BLE_LOG_SPI_MASTER_DMA_CB_ATTR BLE_LOG_STATIC void spi_master_dma_tx_done_cb(spi_transaction_t *spi_trans)
{
/* SPI slave performance issue workaround */
last_tx_done_ts = esp_timer_get_time();
last_tx_done_ts = (uint32_t)esp_timer_get_time();
/* Recycle transport */
ble_log_prph_trans_t *trans = (ble_log_prph_trans_t *)(spi_trans->user);
@@ -47,6 +48,7 @@ BLE_LOG_SPI_MASTER_DMA_CB_ATTR BLE_LOG_STATIC void spi_master_dma_tx_done_cb(spi
BLE_LOG_SPI_MASTER_DMA_CB_ATTR BLE_LOG_STATIC void spi_master_dma_pre_tx_cb(spi_transaction_t *spi_trans)
{
(void)spi_trans;
/* SPI slave performance issue workaround */
while ((esp_timer_get_time() - last_tx_done_ts) < BLE_LOG_SPI_TRANS_ITVL_MIN_US) {}
}
@@ -74,6 +76,7 @@ bool ble_log_prph_init(size_t trans_cnt)
if (spi_bus_initialize(BLE_LOG_SPI_BUS, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) {
goto exit;
}
bus_inited = true;
spi_device_interface_config_t dev_config = {
.clock_speed_hz = SPI_MASTER_FREQ_20M,
@@ -108,8 +111,10 @@ void ble_log_prph_deinit(void)
dev_handle = NULL;
}
/* Note: We don't care if the bus has been inited or not */
spi_bus_free(BLE_LOG_SPI_BUS);
if (bus_inited) {
spi_bus_free(BLE_LOG_SPI_BUS);
bus_inited = false;
}
}
bool ble_log_prph_trans_init(ble_log_prph_trans_t **trans, size_t trans_size)
@@ -10,7 +10,7 @@
/* INCLUDE */
#include "ble_log_prph_spi_master_hd.h"
#include "ble_log_prph_spi_common.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "hal/spi_ll.h"
#include "hal/spi_types.h"
@@ -219,8 +219,7 @@ BLE_LOG_IRAM_ATTR void ble_log_prph_send_trans(ble_log_prph_trans_t *trans)
if (spi_device_queue_trans(dev_handle, &ctx->end, 0) != ESP_OK) {
uint8_t old_status = __atomic_fetch_or(&ctx->status, BLE_LOG_SPI_HD_END_QUEUE_FAILED, __ATOMIC_ACQ_REL);
if (old_status & BLE_LOG_SPI_HD_DATA_DONE) {
/* Data already on the wire: drop it from the buffer so the next
* flush does not re-send these bytes (recycle keeps pos on purpose) */
/* Data is already on the wire; recycle it without re-sending. */
trans->pos = 0;
ble_log_lbm_recycle_trans(trans);
}
@@ -9,7 +9,7 @@
/* INCLUDE */
#include "ble_log_prph_test.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "esp_timer.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
@@ -11,7 +11,8 @@
/* INCLUDE */
#include "ble_log_prph_uart_dma.h"
#include "ble_log.h"
#include "ble_log_lbm.h"
#include "ble_log_lbm_v2.h"
#include "ble_log_rt.h"
#if BLE_LOG_PRPH_UART_DMA_REDIR
@@ -24,10 +25,11 @@
/* MACRO */
#define BLE_LOG_UART_MAX_TRANSFER_SIZE (10240)
#define BLE_LOG_UART_RX_BUF_SIZE (256)
/* ponytail: data burst disabled — UHCI enforces burst-size alignment (addr+len) on
/* ponytail: data burst disabled - UHCI enforces burst-size alignment (addr+len) on
* uhci_transmit() once GDMA weighted arbitration is enabled, and UART log bandwidth
* is baud-rate limited anyway, so burst buys nothing here */
#define BLE_LOG_UART_DMA_BURST_SIZE (1)
#define BLE_LOG_UART_FLUSH_TIMEOUT_TICKS pdMS_TO_TICKS(1000)
#if BLE_LOG_PRPH_UART_DMA_REDIR
#define BLE_LOG_UART_REDIR_BUF_SIZE (512)
#define BLE_LOG_UART_REDIR_FLUSH_PERIOD_US (1000 * 1000)
@@ -38,8 +40,9 @@ BLE_LOG_STATIC BLE_LOG_DRAM_ATTR bool prph_inited = false;
BLE_LOG_STATIC uhci_controller_handle_t dev_handle = NULL;
#if BLE_LOG_PRPH_UART_DMA_REDIR
BLE_LOG_STATIC bool uart_driver_inited = false;
BLE_LOG_STATIC ble_log_lbm_t *redir_lbm = NULL;
BLE_LOG_STATIC ble_log_redir_t *redir_lbm = NULL;
BLE_LOG_STATIC esp_timer_handle_t redir_flush_timer = NULL;
BLE_LOG_STATIC volatile uint32_t redir_writer_count = 0;
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
/* PRIVATE FUNCTION DECLARATION */
@@ -56,20 +59,20 @@ BLE_LOG_IRAM_ATTR BLE_LOG_STATIC bool uart_dma_tx_done_cb(
/* Recycle transport */
ble_log_prph_trans_ctx_t *uart_trans_ctx = (ble_log_prph_trans_ctx_t *)(
(uint8_t *)edata->buffer - sizeof(ble_log_prph_trans_ctx_t)
);
(uint8_t *)edata->buffer - sizeof(ble_log_prph_trans_ctx_t)
);
ble_log_prph_trans_t *trans = uart_trans_ctx->trans;
trans->pos = 0;
ble_log_lbm_recycle_trans(trans);
return true;
}
#if BLE_LOG_PRPH_UART_DMA_REDIR
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void esp_timer_cb_flush_log(void *arg)
BLE_LOG_STATIC void esp_timer_cb_flush_log(void *arg)
{
(void)arg;
if (!prph_inited) {
if (!BLE_LOG_ATOMIC_LOAD_ACQUIRE(prph_inited) ||
!ble_log_lbm_is_enabled()) {
return;
}
@@ -87,7 +90,7 @@ BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void esp_timer_cb_flush_log(void *arg)
bool ble_log_prph_init(size_t trans_cnt)
{
/* Avoid double init */
if (prph_inited) {
if (BLE_LOG_ATOMIC_LOAD_ACQUIRE(prph_inited)) {
return true;
}
@@ -99,8 +102,8 @@ bool ble_log_prph_init(size_t trans_cnt)
.stop_bits = UART_STOP_BITS_1,
};
if ((uart_param_config(CONFIG_BLE_LOG_PRPH_UART_DMA_PORT, &uart_config) != ESP_OK) ||
(uart_set_pin(CONFIG_BLE_LOG_PRPH_UART_DMA_PORT,
CONFIG_BLE_LOG_PRPH_UART_DMA_TX_IO_NUM, -1, -1, -1) != ESP_OK)) {
(uart_set_pin(CONFIG_BLE_LOG_PRPH_UART_DMA_PORT,
CONFIG_BLE_LOG_PRPH_UART_DMA_TX_IO_NUM, -1, -1, -1) != ESP_OK)) {
goto exit;
}
@@ -117,19 +120,18 @@ bool ble_log_prph_init(size_t trans_cnt)
.on_tx_trans_done = uart_dma_tx_done_cb,
};
if ((uhci_new_controller(&uhci_config, &dev_handle) != ESP_OK) ||
(uhci_register_event_callbacks(dev_handle, &uhci_cbs, NULL) != ESP_OK)) {
(uhci_register_event_callbacks(dev_handle, &uhci_cbs, NULL) != ESP_OK)) {
goto exit;
}
/* Redirection is required when utilizing UART port 0 */
/* Redirection is required when utilizing UART port 0 */
#if BLE_LOG_PRPH_UART_DMA_REDIR
/* Initialize a dedicated LBM for redirection */
redir_lbm = (ble_log_lbm_t *)BLE_LOG_MALLOC(sizeof(ble_log_lbm_t));
/* Initialize a dedicated redirection manager (separate from the pool) */
redir_lbm = (ble_log_redir_t *)BLE_LOG_MALLOC(sizeof(ble_log_redir_t));
if (!redir_lbm) {
goto exit;
}
BLE_LOG_MEMSET(redir_lbm, 0, sizeof(ble_log_lbm_t));
redir_lbm->lock_type = BLE_LOG_LBM_LOCK_MUTEX;
BLE_LOG_MEMSET(redir_lbm, 0, sizeof(ble_log_redir_t));
/* Transport initialization */
for (int i = 0; i < BLE_LOG_TRANS_BUF_CNT; i++) {
@@ -137,7 +139,10 @@ bool ble_log_prph_init(size_t trans_cnt)
BLE_LOG_UART_REDIR_BUF_SIZE)) {
goto exit;
}
redir_lbm->trans[i]->owner = (void *)redir_lbm;
/* Redirection transports are not part of the global pool. */
redir_lbm->trans[i]->id = BLE_LOG_TRANS_ID_NONE;
redir_lbm->trans[i]->owner_kind = BLE_LOG_TRANS_OWNER_REDIR;
redir_lbm->trans[i]->state = BLE_LOG_TRANS_STATE_FREE;
}
/* Mutex initialization */
@@ -146,11 +151,13 @@ bool ble_log_prph_init(size_t trans_cnt)
goto exit;
}
/* Initialize UART driver for redirection */
/* Initialize UART driver for redirection. */
if (!uart_is_driver_installed(UART_NUM_0)) {
if (uart_driver_install(UART_NUM_0, BLE_LOG_UART_RX_BUF_SIZE, 0, 0, NULL, 0) == ESP_OK) {
uart_driver_inited = true;
if (uart_driver_install(UART_NUM_0, BLE_LOG_UART_RX_BUF_SIZE,
0, 0, NULL, 0) != ESP_OK) {
goto exit;
}
uart_driver_inited = true;
}
uart_vfs_dev_use_driver(UART_NUM_0);
@@ -158,15 +165,19 @@ bool ble_log_prph_init(size_t trans_cnt)
esp_timer_create_args_t timer_args = {
.callback = esp_timer_cb_flush_log,
.dispatch_method = ESP_TIMER_TASK,
.skip_unhandled_events = true,
};
if (esp_timer_create(&timer_args, &redir_flush_timer) != ESP_OK) {
goto exit;
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
prph_inited = true;
BLE_LOG_ATOMIC_STORE_RELEASE(prph_inited, true);
#if BLE_LOG_PRPH_UART_DMA_REDIR
esp_timer_start_periodic(redir_flush_timer, BLE_LOG_UART_REDIR_FLUSH_PERIOD_US);
if (esp_timer_start_periodic(redir_flush_timer,
BLE_LOG_UART_REDIR_FLUSH_PERIOD_US) != ESP_OK) {
goto exit;
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
return true;
@@ -178,27 +189,45 @@ exit:
void ble_log_prph_deinit(void)
{
prph_inited = false;
__atomic_store_n(&prph_inited, false, __ATOMIC_SEQ_CST);
#if BLE_LOG_PRPH_UART_DMA_REDIR
/* Release flush timer */
if (redir_flush_timer) {
esp_timer_stop(redir_flush_timer);
esp_timer_stop_blocking(redir_flush_timer, portMAX_DELAY);
esp_timer_delete(redir_flush_timer);
redir_flush_timer = NULL;
}
/* Delete UART driver if it's installed by current module */
if (uart_driver_inited) {
uart_driver_delete(UART_NUM_0);
while (__atomic_load_n(&redir_writer_count, __ATOMIC_SEQ_CST) > 0) {
vTaskDelay(1);
}
/* Release redirection LBM */
/* Flush redirection buffers before waiting for all submitted DMA. */
if (redir_lbm) {
if (redir_lbm->mutex) {
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
ble_log_lbm_stream_flush(redir_lbm, BLE_LOG_SRC_REDIR);
xSemaphoreGive(redir_lbm->mutex);
}
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
if (dev_handle) {
uhci_wait_all_tx_transaction_done(dev_handle, portMAX_DELAY);
}
#if BLE_LOG_PRPH_UART_DMA_REDIR
/* Restore the VFS before deleting a driver installed by this module. */
if (uart_driver_inited) {
uart_vfs_dev_use_nonblocking(UART_NUM_0);
uart_driver_delete(UART_NUM_0);
uart_driver_inited = false;
}
/* Release redirection LBM only after DMA callbacks have completed. */
if (redir_lbm) {
if (redir_lbm->mutex) {
vSemaphoreDelete(redir_lbm->mutex);
}
@@ -214,7 +243,6 @@ void ble_log_prph_deinit(void)
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
if (dev_handle) {
uhci_wait_all_tx_transaction_done(dev_handle, portMAX_DELAY);
uhci_del_controller(dev_handle);
dev_handle = NULL;
}
@@ -277,67 +305,102 @@ void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans)
BLE_LOG_IRAM_ATTR void ble_log_prph_send_trans(ble_log_prph_trans_t *trans)
{
if (uhci_transmit(dev_handle, trans->buf, trans->pos) != ESP_OK) {
/* No tx_done will fire on failure: recycle here to avoid leaking. */
ble_log_lbm_recycle_trans(trans);
}
}
/* Redirection is required when utilizing UART port 0 */
#if BLE_LOG_PRPH_UART_DMA_REDIR
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
void ble_log_redir_uart_tx_chars(const char *src, size_t len)
BLE_LOG_STATIC
bool ble_log_redir_uart_tx_chars(const char *src, size_t len)
{
if (BLE_LOG_IN_ISR() || xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
return;
__atomic_add_fetch(&redir_writer_count, 1, __ATOMIC_SEQ_CST);
if (!__atomic_load_n(&prph_inited, __ATOMIC_SEQ_CST) ||
!ble_log_lbm_is_enabled()) {
__atomic_sub_fetch(&redir_writer_count, 1, __ATOMIC_SEQ_CST);
return false;
}
if (BLE_LOG_IN_ISR() || xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
__atomic_sub_fetch(&redir_writer_count, 1, __ATOMIC_SEQ_CST);
return true;
}
uint32_t timestamp = (uint32_t)esp_timer_get_time();
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
ble_log_lbm_stream_write(redir_lbm, BLE_LOG_SRC_REDIR,
(const uint8_t *)src, len);
ble_log_lbm_stream_write(redir_lbm, BLE_LOG_SRC_REDIR, timestamp,
(const uint8_t *)src, len);
xSemaphoreGive(redir_lbm->mutex);
__atomic_sub_fetch(&redir_writer_count, 1, __ATOMIC_SEQ_CST);
return true;
}
int __real_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len);
int __wrap_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len)
{
if (!prph_inited || (uart_num != UART_NUM_0)) {
if ((uart_num != UART_NUM_0) ||
!ble_log_redir_uart_tx_chars(buffer, len)) {
return __real_uart_tx_chars(uart_num, buffer, len);
}
ble_log_redir_uart_tx_chars(buffer, len);
return len;
}
int __real_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size);
int __wrap_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size)
{
if (!prph_inited || (uart_num != UART_NUM_0)) {
if ((uart_num != UART_NUM_0) ||
!ble_log_redir_uart_tx_chars(src, size)) {
return __real_uart_write_bytes(uart_num, src, size);
}
ble_log_redir_uart_tx_chars(src, size);
return size;
}
int __real_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len);
int __wrap_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len)
{
if (!prph_inited || (uart_num != UART_NUM_0)) {
if ((uart_num != UART_NUM_0) ||
!ble_log_redir_uart_tx_chars(src, size)) {
return __real_uart_write_bytes_with_break(uart_num, src, size, brk_len);
} else {
(void)brk_len;
return __wrap_uart_write_bytes(uart_num, src, size);
}
return size;
}
ble_log_lbm_t *ble_log_prph_get_redir_lbm(void)
BLE_LOG_IRAM_ATTR ble_log_redir_t *ble_log_prph_get_redir_lbm(void)
{
return redir_lbm;
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
#if BLE_LOG_PRPH_UART_DMA_REDIR
bool ble_log_prph_flush(void)
{
while (__atomic_load_n(&redir_writer_count, __ATOMIC_SEQ_CST) > 0) {
vTaskDelay(1);
}
if (!redir_lbm) {
return true;
}
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
ble_log_lbm_stream_flush(redir_lbm, BLE_LOG_SRC_REDIR);
xSemaphoreGive(redir_lbm->mutex);
(void)ble_log_rt_drain();
TickType_t start_tick = xTaskGetTickCount();
while (BLE_LOG_ATOMIC_LOAD_ACQUIRE(redir_lbm->inflight) > 0) {
if ((xTaskGetTickCount() - start_tick) >= BLE_LOG_UART_FLUSH_TIMEOUT_TICKS) {
return false;
}
vTaskDelay(1);
}
return true;
}
void ble_log_prph_reset_util_counters(void)
{
#if BLE_LOG_PRPH_UART_DMA_REDIR
if (redir_lbm) {
__atomic_store_n(&redir_lbm->trans_inflight, 0, __ATOMIC_RELAXED);
__atomic_store_n(&redir_lbm->trans_inflight_peak, 0, __ATOMIC_RELAXED);
uint32_t inflight = BLE_LOG_ATOMIC_LOAD_RELAXED(redir_lbm->inflight);
BLE_LOG_ATOMIC_STORE_RELAXED(redir_lbm->inflight_peak, inflight);
}
#endif
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
@@ -14,6 +14,7 @@
typedef struct {
ble_log_src_t src;
uint8_t source_meta;
uint32_t sn;
const uint8_t *payload;
size_t payload_len;
@@ -14,6 +14,7 @@
typedef struct {
ble_log_src_t src;
uint8_t source_meta;
uint32_t sn;
const uint8_t *payload;
size_t payload_len;
@@ -14,6 +14,7 @@
typedef struct {
ble_log_src_t src;
uint8_t source_meta;
uint32_t sn;
const uint8_t *payload;
size_t payload_len;
@@ -99,9 +99,9 @@ void hci_host_send_packet(uint8_t *data, uint16_t len)
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len);
#endif // CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
#if CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
#if CONFIG_BLE_LOG_HCI_LOG_ENABLED
ble_log_write_hci(BLE_LOG_HCI_DOWNSTREAM, data, len);
#endif /* CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED */
#endif /* CONFIG_BLE_LOG_HCI_LOG_ENABLED */
#if (BT_CONTROLLER_INCLUDED == TRUE)
esp_vhci_host_send_packet(data, len);
#else /* BT_CONTROLLER_INCLUDED == TRUE */
@@ -619,9 +619,9 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len)
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_UPSTREAM, data, len);
#endif // CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
#if CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
#if CONFIG_BLE_LOG_HCI_LOG_ENABLED
ble_log_write_hci(BLE_LOG_HCI_UPSTREAM, data, len);
#endif /* CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED */
#endif /* CONFIG_BLE_LOG_HCI_LOG_ENABLED */
//Target has packet to host, malloc new buffer for packet
BT_HDR *pkt = NULL;
#if (BLE_42_SCAN_EN == TRUE)
@@ -87,9 +87,9 @@ void esp_vhci_host_send_packet_wrapper(uint8_t *data, uint16_t len)
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len);
#endif // CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
#if CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
#if CONFIG_BLE_LOG_HCI_LOG_ENABLED
ble_log_write_hci(BLE_LOG_HCI_DOWNSTREAM, data, len);
#endif /* CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED */
#endif /* CONFIG_BLE_LOG_HCI_LOG_ENABLED */
esp_vhci_host_send_packet(data, len);
}
@@ -274,9 +274,9 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len)
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_UPSTREAM, data, len);
#endif // CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
#if CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED
#if CONFIG_BLE_LOG_HCI_LOG_ENABLED
ble_log_write_hci(BLE_LOG_HCI_UPSTREAM, data, len);
#endif /* CONFIG_BLE_LOG_HOST_SIDE_HCI_LOG_ENABLED */
#endif /* CONFIG_BLE_LOG_HCI_LOG_ENABLED */
bt_record_hci_data(data, len);