Merge branch 'feat/ble_log_v2_v5.4' into 'release/v5.4'

feat(ble): refactored ble log module with layered design (v5.4)

See merge request espressif/esp-idf!41658
This commit is contained in:
Island
2025-09-03 14:18:26 +08:00
21 changed files with 2745 additions and 0 deletions

View File

@@ -136,6 +136,42 @@ if(CONFIG_BT_ENABLED)
"common/ble_log/ble_log_spi_out.c"
)
# BLE Log Module
if(CONFIG_BLE_LOG_ENABLED)
# Core source files
list(APPEND srcs
common/ble_log/src/ble_log.c
common/ble_log/src/ble_log_lbm.c
common/ble_log/src/ble_log_rt.c
common/ble_log/src/ble_log_util.c
)
# Includes
list(APPEND include_dirs
common/ble_log/include
)
# Private includes
list(APPEND priv_include_dirs
common/ble_log/src/internal_include
common/ble_log/src/internal_include/prph
)
# Timestamp synchronization extension
if(CONFIG_BLE_LOG_TS_ENABLED)
list(APPEND srcs common/ble_log/src/ble_log_ts.c)
endif()
# Peripheral interface implementation
if(CONFIG_BLE_LOG_PRPH_DUMMY)
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_dummy.c)
elseif(CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA)
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_spi_master_dma.c)
elseif(CONFIG_BLE_LOG_PRPH_UART_DMA)
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_uart_dma.c)
endif()
endif()
# Host Bluedroid
if(CONFIG_BT_BLUEDROID_ENABLED)
@@ -928,6 +964,13 @@ if(CONFIG_BT_ENABLED)
if(CONFIG_BT_LE_CONTROLLER_LOG_WRAP_PANIC_HANDLER_ENABLE)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=esp_panic_handler")
endif()
if(DEFINED CONFIG_BLE_LOG_PRPH_UART_DMA_PORT)
if(CONFIG_BLE_LOG_PRPH_UART_DMA_PORT EQUAL 0)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_tx_chars")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes_with_break")
endif()
endif()
if(CONFIG_IDF_TARGET_ESP32C6)
add_prebuilt_library(libble_app
"${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c6/esp32c6-bt-lib/esp32c6/libble_app.a"

View File

@@ -6,6 +6,10 @@ config BT_ALARM_MAX_NUM
This option decides the maximum number of alarms which
could be used by Bluetooth host.
menu "BLE Log"
source "$IDF_PATH/components/bt/common/ble_log/Kconfig.in"
endmenu
config BT_BLE_LOG_SPI_OUT_ENABLED
bool "Output ble logs to SPI bus (Experimental)"
default n

View File

@@ -0,0 +1,147 @@
config BLE_LOG_ENABLED
bool "Enable BLE Log Module (Experimental)"
default n
help
Enable BLE Log Module
if BLE_LOG_ENABLED
config BLE_LOG_LBM_TRANS_SIZE
int "Buffer size for each peripheral transport"
default 512
help
There're 2 log buffer managers (LBMs) with compare-and-swap
(CAS) protection, 1 LBM with FreeRTOS mutex protection, 1 LBM
without protection for critical section. Each LBM is managing
2 ping-pong buffers, which means there will be 4 * 2 *
BLE_LOG_LBM_TRANS_SIZE bytes buffer allocated
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"
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.
config BLE_LOG_LL_ENABLED
bool "Enable BLE Log for Link Layer"
depends on BT_CONTROLLER_ENABLED
default y
select BT_LE_CONTROLLER_LOG_ENABLED
select BT_LE_CONTROLLER_LOG_MODE_BLE_LOG
help
Enable BLE Log for Link Layer
config BLE_LOG_LBM_LL_TRANS_SIZE
int "Buffer size for each peripheral transport of Link Layer LBM"
depends on BLE_LOG_LL_ENABLED
default 1024
help
There're 2 Link Layer dedicated log buffer managers (LBMs) with
compare-and-swap (CAS) protection. Each LBM is managing 2 ping-
pong buffers, which means there will be additional 2 * 2 *
BLE_LOG_LBM_LL_TRANS_SIZE bytes buffer allocated
config BLE_LOG_PAYLOAD_CHECKSUM_ENABLED
bool "Enable payload checksum for BLE Log data integrity check"
default y
help
Checksum is the default method for BLE Log data integrity check,
but for targets with slow CPU speed, it may cause significant system
performance decrease; a compromise could be made to balance the
realtime performance and log data integrity, which is calculating the
checksum of frame head and payload all together by default, or only
calculate the checksum of frame head to minimize performance decrease
config BLE_LOG_ENH_STAT_ENABLED
bool "Enable enhanced statistics for BLE Log"
default n
help
Enable enhanced statistics for written/lost frame/bytes count, which may
cost additional ~100kB memory
config BLE_LOG_TS_ENABLED
bool "Enable BLE Log Timestamp Synchronization (TS)"
default n
help
Enable BLE Log TS with external logging module
config BLE_LOG_SYNC_IO_NUM
int "GPIO number for Timestamp Synchronization (TS) toggle output"
depends on BLE_LOG_TS_ENABLED
default 0
help
GPIO number for TS toggle output
choice BLE_LOG_PRPH_CHOICE
prompt "BLE Log peripheral choice"
default BLE_LOG_PRPH_DUMMY
help
Choose BLE Log peripheral
config BLE_LOG_PRPH_DUMMY
bool "Dummy transport"
help
Dummy transport (dump only)
config BLE_LOG_PRPH_SPI_MASTER_DMA
bool "Utilize SPI master DMA driver as transport"
help
Utilize SPI master DMA driver as transport
config BLE_LOG_PRPH_UART_DMA
bool "Utilize UART DMA driver as transport"
help
Utilize UART DMA driver as transport
endchoice
if BLE_LOG_PRPH_SPI_MASTER_DMA
config BLE_LOG_PRPH_SPI_MASTER_DMA_MOSI_IO_NUM
int "GPIO number of MOSI port for SPI master DMA transport"
default 0
help
GPIO number of MOSI port for SPI master DMA transport
config BLE_LOG_PRPH_SPI_MASTER_DMA_SCLK_IO_NUM
int "GPIO number of SCLK port for SPI master DMA transport"
default 0
help
GPIO number of SCLK port for SPI master DMA transport
config BLE_LOG_PRPH_SPI_MASTER_DMA_CS_IO_NUM
int "GPIO number of CS port for SPI master DMA transport"
default 0
help
GPIO number of CS port for SPI master DMA transport
endif
if BLE_LOG_PRPH_UART_DMA
config BLE_LOG_PRPH_UART_DMA_PORT
int "UART port number for UART DMA transport"
default 0
help
UART port number for UART DMA
config BLE_LOG_PRPH_UART_DMA_BAUD_RATE
int "Baud rate of UART port for UART DMA transport"
default 921600
help
Determine the baud rate of UART port
config BLE_LOG_PRPH_UART_DMA_TX_IO_NUM
int "GPIO number for UART TX"
default 0
help
GPIO number for UART TX
endif
endif

View File

@@ -0,0 +1,450 @@
# BLE Log Module
A high-performance, modular Bluetooth logging system that provides real-time log capture and transmission capabilities for the ESP-IDF Bluetooth stack.
## Table of Contents
- [Overview](#overview)
- [Architecture Design](#architecture-design)
- [Features](#features)
- [Quick Start](#quick-start)
- [Configuration Options](#configuration-options)
- [API Reference](#api-reference)
- [Usage Examples](#usage-examples)
- [Performance & Memory Optimization](#performance--memory-optimization)
- [Troubleshooting](#troubleshooting)
- [Important Notes](#important-notes)
## Overview
The BLE Log module is an efficient logging system specifically designed for the ESP-IDF Bluetooth stack, supporting real-time log capture, multi-source log collection, and various transmission methods. This module has been refactored with a modular design, featuring high-concurrency processing capabilities and low-latency characteristics.
### Main Components
- **BLE Log Core** (`ble_log.c`): Module core responsible for initialization and coordination of sub-modules
- **Runtime Manager** (`ble_log_rt.c`): Runtime task management for log transmission scheduling
- **Log Buffer Manager** (`ble_log_lbm.c`): Log buffer management supporting multiple locking mechanisms
- **Peripheral Interface** (`ble_log_prph_*.c`): Peripheral interface abstraction layer supporting various transmission methods
- **Timestamp Sync** (`ble_log_ts.c`): Timestamp synchronization module
- **Utility** (`ble_log_util.c`): Common utility functions
## Features
### Core Functionality
- **Multi-source Log Collection**: Supports multiple log sources including Link Layer, Host, HCI, etc.
- **High Concurrency Processing**: Uses atomic and spin lock mechanisms for multi-task concurrent writing
- **Real-time Transmission**: Asynchronous transmission mechanism based on FreeRTOS tasks
- **Data Integrity**: Configurable checksum mechanism ensures data integrity
- **Memory Optimization**: Ping-pong buffer design minimizes memory usage
### Advanced Features
- **Timestamp Synchronization**: Supports timestamp synchronization with external devices (optional)
- **Enhanced Statistics**: Detailed logging statistics including loss rate analysis (optional)
- **Link Layer Integration**: Deep integration with ESP-IDF Bluetooth Link Layer
- **Multiple Transmission Methods**: Supports SPI DMA, UART DMA, and Dummy transmission
### Performance Features
- **IRAM Optimization**: Critical path code runs in IRAM ensuring low latency
- **Lock-free Design**: Most operations use atomic operations reducing lock contention
- **Buffer Reuse**: Intelligent buffer management reduces memory allocation overhead
## Quick Start
### 1. Enable Module
Enable the BLE Log module in `menuconfig`:
```
Component config → Bluetooth → Enable BLE Log Module (Experimental)
```
### 2. Basic Configuration
```c
#include "ble_log.h"
void app_main() {
// Initialize BLE Log module
if (!ble_log_init()) {
ESP_LOGE(TAG, "Failed to initialize BLE Log");
return;
}
// Write log data
uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, data, sizeof(data));
// Force flush buffers
ble_log_flush();
// Cleanup resources
ble_log_deinit();
}
```
### 3. Link Layer Integration
When `CONFIG_BLE_LOG_LL_ENABLED` is enabled, Link Layer logs are automatically integrated:
```c
// Link Layer logs will automatically call this function
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
uint32_t len_append, const uint8_t *addr_append,
uint32_t flag);
```
## Configuration Options
### Basic Configuration
| Configuration | Default | Description |
|---------------|---------|-------------|
| `CONFIG_BLE_LOG_ENABLED` | n | Enable BLE Log module |
| `CONFIG_BLE_LOG_LBM_TRANS_SIZE` | 512 | Size of each transport buffer |
| `CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT` | 2 | Number of atomic lock LBMs for task context |
| `CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT` | 1 | Number of atomic lock LBMs for ISR context |
### Link Layer Configuration
| Configuration | Default | Description |
|---------------|---------|-------------|
| `CONFIG_BLE_LOG_LL_ENABLED` | y | Enable Link Layer logging |
| `CONFIG_BLE_LOG_LBM_LL_TRANS_SIZE` | 1024 | Link Layer transport buffer size |
### Advanced Features
| Configuration | Default | Description |
|---------------|---------|-------------|
| `CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED` | y | Enable payload checksum |
| `CONFIG_BLE_LOG_ENH_STAT_ENABLED` | n | Enable enhanced statistics |
| `CONFIG_BLE_LOG_TS_ENABLED` | n | Enable timestamp synchronization |
### Transport Method Configuration
| Transport | Configuration | Description |
|-----------|---------------|-------------|
| Dummy | `CONFIG_BLE_LOG_PRPH_DUMMY` | Debug dummy transport |
| SPI Master DMA | `CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA` | SPI DMA transport |
| UART DMA | `CONFIG_BLE_LOG_PRPH_UART_DMA` | UART DMA transport |
## API Reference
### Core API
#### `bool ble_log_init(void)`
Initialize the BLE Log module.
**Return Value**:
- `true`: Initialization successful
- `false`: Initialization failed
**Note**: Must be called before using any other APIs.
#### `void ble_log_deinit(void)`
Cleanup the BLE Log module and release all resources.
**Note**:
- All pending logs will be lost after calling this function
- Peripheral interface will be cleaned up first to avoid DMA transmission issues during memory release
#### `bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len)`
Write hexadecimal log data.
**Parameters**:
- `src_code`: Log source code
- `addr`: Data pointer
- `len`: Data length
**Return Value**:
- `true`: Write successful
- `false`: Write failed (module not initialized or insufficient buffer)
#### `void ble_log_flush(void)`
Force flush all buffers and send pending logs immediately.
**Note**: This operation is blocking and will pause module operation until all buffers are cleared.
#### `void ble_log_dump_to_console(void)`
Output all buffer contents to console in hexadecimal format for debugging.
### Log Source Types
```c
typedef enum {
BLE_LOG_SRC_INTERNAL = 0, // Internal system logs
BLE_LOG_SRC_CUSTOM, // User-defined logs
BLE_LOG_SRC_LL_TASK, // Link Layer task logs
BLE_LOG_SRC_LL_HCI, // Link Layer HCI logs
BLE_LOG_SRC_LL_ISR, // Link Layer interrupt logs
BLE_LOG_SRC_HOST, // Host layer logs
BLE_LOG_SRC_HCI, // HCI layer logs
BLE_LOG_SRC_ENCODE, // Encoding layer logs
BLE_LOG_SRC_MAX,
} ble_log_src_t;
```
### Link Layer API (Conditional Compilation)
#### `void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr, uint32_t len_append, const uint8_t *addr_append, uint32_t flag)`
Link Layer dedicated log writing interface.
**Parameters**:
- `len`: Main data length
- `addr`: Main data pointer
- `len_append`: Append data length
- `addr_append`: Append data pointer
- `flag`: Log flag bits
**Flag Definitions**:
```c
enum {
BLE_LOG_LL_FLAG_CONTINUE = 0,
BLE_LOG_LL_FLAG_END,
BLE_LOG_LL_FLAG_TASK,
BLE_LOG_LL_FLAG_ISR,
BLE_LOG_LL_FLAG_HCI,
BLE_LOG_LL_FLAG_RAW,
BLE_LOG_LL_FLAG_HCI_UPSTREAM,
};
```
### Timestamp Synchronization API (Conditional Compilation)
#### `bool ble_log_sync_enable(bool enable)`
Enable or disable timestamp synchronization functionality.
**Parameters**:
- `enable`: true to enable, false to disable
**Return Value**:
- `true`: Operation successful
- `false`: Operation failed (module not initialized)
## Usage Examples
### Example 1: Basic Logging
```c
#include "ble_log.h"
void example_basic_logging() {
// Initialize
if (!ble_log_init()) {
printf("BLE Log init failed\n");
return;
}
// Log some example data
uint8_t hci_cmd[] = {0x01, 0x03, 0x0C, 0x00}; // HCI Reset Command
ble_log_write_hex(BLE_LOG_SRC_HCI, hci_cmd, sizeof(hci_cmd));
uint8_t host_data[] = {0x02, 0x00, 0x20, 0x0B, 0x00, 0x07, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28};
ble_log_write_hex(BLE_LOG_SRC_HOST, host_data, sizeof(host_data));
// Force send
ble_log_flush();
// Cleanup
ble_log_deinit();
}
```
### Example 2: ISR Context Logging
```c
void IRAM_ATTR some_isr_handler() {
uint8_t isr_data[] = {0xDE, 0xAD, 0xBE, 0xEF};
// Safe to write logs in ISR context
ble_log_write_hex(BLE_LOG_SRC_LL_ISR, isr_data, sizeof(isr_data));
}
```
### Example 3: Logging with Timestamp Synchronization
```c
void example_with_timestamp_sync() {
if (!ble_log_init()) {
return;
}
#if CONFIG_BLE_LOG_TS_ENABLED
// Enable timestamp synchronization
ble_log_sync_enable(true);
#endif
// Log data...
uint8_t data[] = {0x01, 0x02, 0x03};
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, data, sizeof(data));
// Timestamp information will be automatically included in logs
ble_log_deinit();
}
```
### Example 4: Performance Testing
```c
void example_performance_test() {
if (!ble_log_init()) {
return;
}
uint8_t test_data[100];
for (int i = 0; i < 100; i++) {
test_data[i] = i;
}
uint32_t start_time = esp_timer_get_time();
// Send 1000 logs
for (int i = 0; i < 1000; i++) {
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, test_data, sizeof(test_data));
}
ble_log_flush();
uint32_t end_time = esp_timer_get_time();
printf("Time to write 1000 logs: %lu us\n", end_time - start_time);
ble_log_deinit();
}
```
## Performance & Memory Optimization
### Memory Usage Estimation
Memory usage under default configuration:
```
Total Buffers = (Atomic Task LBMs + Atomic ISR LBMs + Spin LBMs) × 2 × Transport Buffer Size
Default Config = (2 + 1 + 2) × 2 × 512 = 5120 bytes
Additional when Link Layer enabled:
LL Buffers = 2 × 2 × 1024 = 4096 bytes
Additional when Enhanced Statistics enabled:
Statistics Data = Log Source Count × sizeof(ble_log_stat_mgr_t) = 8 × 40 = 320 bytes
```
### Performance Optimization Recommendations
1. **Adjust LBM Count**: Adjust atomic lock LBM count based on concurrency requirements
2. **Buffer Size**: Adjust transport buffer size based on log volume
3. **Transport Method**: Choose optimal transport method based on hardware (SPI DMA typically has best performance)
4. **Checksum**: Consider disabling payload checksum when performance requirements are extremely high
### Real-time Considerations
- Critical code paths are marked with `BLE_LOG_IRAM_ATTR` and run in IRAM
- Atomic operations avoid lock contention
- Ping-pong buffers ensure continuous writing
## Troubleshooting
### Common Issues
#### 1. Initialization Failure
**Symptoms**: `ble_log_init()` returns `false`
**Possible Causes**:
- Insufficient memory
- Peripheral configuration error
- Duplicate initialization
**Solutions**:
```c
// Check available memory
printf("Free heap: %d bytes\n", esp_get_free_heap_size());
// Ensure initialization only happens once
static bool initialized = false;
if (!initialized) {
initialized = ble_log_init();
}
```
#### 2. Log Loss
**Symptoms**: Some logs don't appear in output
**Possible Causes**:
- Buffer overflow
- Transmission speed can't keep up with write speed
- Module not properly initialized
**Solutions**:
```c
// Enable enhanced statistics to check loss rate
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
// Statistics will be automatically included in logs
#endif
// Adjust buffer size
// CONFIG_BLE_LOG_LBM_TRANS_SIZE=1024
// Increase atomic lock LBM count
// CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT=4
```
#### 3. Performance Issues
**Symptoms**: System response becomes slow
**Possible Causes**:
- Checksum calculation overhead
- Transmission bottleneck
- Lock contention
**Solutions**:
```c
// Disable payload checksum
// CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED=n
// Use faster transmission method
// CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA=y
// Adjust task priority
#define BLE_LOG_TASK_PRIO configMAX_PRIORITIES-3
```
### Debugging Techniques
#### 1. Use Dummy Transport for Debugging
```c
// Select Dummy transport in menuconfig
// Then use dump function to view buffer contents
ble_log_dump_to_console();
```
#### 2. Enable Enhanced Statistics
```c
// Enable in menuconfig
// CONFIG_BLE_LOG_ENH_STAT_ENABLED=y
// Statistics will be automatically output to logs
```
#### 3. Monitor Memory Usage
```c
void monitor_memory() {
printf("Free heap before init: %d\n", esp_get_free_heap_size());
ble_log_init();
printf("Free heap after init: %d\n", esp_get_free_heap_size());
}
```

View File

@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_H__
#define __BLE_LOG_H__
/* ------- */
/* BLE Log */
/* ------- */
/* INCLUDE */
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
/* TYPEDEF */
/* CRITICAL:
* 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 */
typedef enum {
/* Internal */
BLE_LOG_SRC_INTERNAL = 0,
/* Custom */
BLE_LOG_SRC_CUSTOM,
/* BLE Stack */
BLE_LOG_SRC_LL_TASK,
BLE_LOG_SRC_LL_HCI,
BLE_LOG_SRC_LL_ISR,
BLE_LOG_SRC_HOST,
BLE_LOG_SRC_HCI,
BLE_LOG_SRC_ENCODE,
BLE_LOG_SRC_MAX,
} ble_log_src_t;
/* INTERFACE */
bool ble_log_init(void);
void ble_log_deinit(void);
bool ble_log_enable(bool enable);
void ble_log_flush(void);
bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t 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,
uint32_t len_append, const uint8_t *addr_append, uint32_t flag);
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
#if CONFIG_BLE_LOG_TS_ENABLED
bool ble_log_sync_enable(bool enable);
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
#endif /* __BLE_LOG_H__ */

View File

@@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ------- */
/* BLE Log */
/* ------- */
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_rt.h"
#include "ble_log_lbm.h"
#include "ble_log_prph.h"
#include "ble_log_util.h"
#if CONFIG_BLE_LOG_TS_ENABLED
#include "ble_log_ts.h"
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
/* VARIABLE */
BLE_LOG_STATIC bool ble_log_inited = false;
/* INTERFACE */
bool ble_log_init(void)
{
/* Avoid double init */
if (ble_log_inited) {
return true;
}
#if CONFIG_BLE_LOG_TS_ENABLED
/* Initialize BLE Log TS */
if (!ble_log_ts_init()) {
goto exit;
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
/* Initialize BLE Log Runtime */
if (!ble_log_rt_init()) {
goto exit;
}
/* Initialize BLE Log LBM */
if (!ble_log_lbm_init()) {
goto exit;
}
/* Initialize BLE Log peripheral interface */
if (!ble_log_prph_init(BLE_LOG_LBM_CNT)) {
goto exit;
}
/* Initialization done */
ble_log_inited = true;
ble_log_enable(true);
/* 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:
ble_log_deinit();
return false;
}
void ble_log_deinit(void)
{
ble_log_enable(false);
ble_log_inited = false;
/* CRITICAL:
* BLE Log peripheral interface must be deinitialized at first,
* because there's a risky scenario that may cause severe peripheral
* driver fault - if a log buffer is sent to peripheral driver, and
* ble_log_deinit is called; in this case, if LBM is deinitialized
* before peripheral interface, the log buffer may be freed before
* peripheral driver completing tx, and the result would be faulty */
ble_log_prph_deinit();
/* Deinitialize BLE Log LBM */
ble_log_lbm_deinit();
/* Deinitialize BLE Log Runtime */
ble_log_rt_deinit();
#if CONFIG_BLE_LOG_TS_ENABLED
/* Deinitialize BLE Log TS */
ble_log_ts_deinit();
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
}

View File

@@ -0,0 +1,543 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ------------------------------- */
/* BLE Log - Log Buffer Management */
/* ------------------------------- */
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_lbm.h"
#include "ble_log_rt.h"
/* VARIABLE */
BLE_LOG_STATIC volatile uint32_t lbm_ref_count = 0;
BLE_LOG_STATIC bool lbm_inited = false;
BLE_LOG_STATIC bool lbm_enabled = false;
BLE_LOG_STATIC ble_log_lbm_ctx_t *lbm_ctx = NULL;
BLE_LOG_STATIC ble_log_stat_mgr_t *stat_mgr_ctx[BLE_LOG_SRC_MAX] = {0};
/* PRIVATE FUNCTION DECLARATION */
BLE_LOG_STATIC ble_log_lbm_t *ble_log_lbm_acquire(void);
BLE_LOG_STATIC void ble_log_lbm_release(ble_log_lbm_t *lbm);
BLE_LOG_STATIC
void ble_log_lbm_write_trans(ble_log_prph_trans_t **trans, ble_log_src_t src_code,
const uint8_t *addr, uint16_t len,
const uint8_t *addr_append, uint16_t len_append);
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
BLE_LOG_STATIC void ble_log_stat_mgr_update(ble_log_src_t src_code, uint32_t len, bool lost);
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* ------------------------- */
/* PRIVATE INTERFACE */
/* ------------------------- */
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
ble_log_lbm_t *ble_log_lbm_acquire(void)
{
ble_log_lbm_t *lbm = NULL;
ble_log_lbm_t *atomic_pool;
ble_log_lbm_t *spin_lbm;
int atomic_pool_size;
if (BLE_LOG_IN_ISR()) {
atomic_pool = lbm_ctx->atomic_pool_isr;
spin_lbm = &(lbm_ctx->spin_isr);
atomic_pool_size = BLE_LOG_LBM_ATOMIC_ISR_CNT;
} else {
atomic_pool = lbm_ctx->atomic_pool_task;
spin_lbm = &(lbm_ctx->spin_task);
atomic_pool_size = BLE_LOG_LBM_ATOMIC_TASK_CNT;
}
/* Try to acquire atomic LBM first */
for (int i = 0; i < atomic_pool_size; i++) {
lbm = &atomic_pool[i];
if (ble_log_cas_acquire(&(lbm->atomic_lock))) {
return lbm;
}
}
/* Fallback to spinlock LBM */
lbm = spin_lbm;
BLE_LOG_ACQUIRE_SPIN_LOCK(&(lbm->spin_lock));
return lbm;
}
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
void ble_log_lbm_release(ble_log_lbm_t *lbm)
{
switch (lbm->lock_type) {
case BLE_LOG_LBM_LOCK_ATOMIC:
ble_log_cas_release(&(lbm->atomic_lock));
break;
case BLE_LOG_LBM_LOCK_SPIN:
BLE_LOG_RELEASE_SPIN_LOCK(&lbm->spin_lock);
break;
case BLE_LOG_LBM_LOCK_NONE:
default:
break;
}
}
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
void ble_log_lbm_write_trans(ble_log_prph_trans_t **trans, ble_log_src_t src_code,
const uint8_t *addr, uint16_t len,
const uint8_t *addr_append, uint16_t len_append)
{
/* Preparation before writing */
uint8_t *buf = (*trans)->buf + (*trans)->pos;
uint16_t payload_len = len + len_append;
ble_log_stat_mgr_t *stat_mgr = stat_mgr_ctx[src_code];
uint32_t frame_sn = BLE_LOG_GET_FRAME_SN(&(stat_mgr->frame_sn));
ble_log_frame_head_t frame_head = {
.length = payload_len,
.frame_meta = BLE_LOG_MAKE_FRAME_META(src_code, frame_sn),
};
/* Memory operation */
BLE_LOG_MEMCPY(buf, &frame_head, BLE_LOG_FRAME_HEAD_LEN);
if (len) {
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN, addr, len);
}
if (len_append) {
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN + len, addr_append, len_append);
}
/* Data integrity check */
#if CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED
uint32_t checksum = ble_log_fast_checksum((const uint8_t *)buf, BLE_LOG_FRAME_HEAD_LEN + payload_len);
#else /* !CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED */
/* Note:
* Minimum data integrity check is still required for log parsing reliability,
* which can be achieved by validating the checksum of frame head only */
uint32_t checksum = ble_log_fast_checksum((const uint8_t *)buf, BLE_LOG_FRAME_HEAD_LEN);
#endif /* CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED */
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN + payload_len, &checksum, BLE_LOG_FRAME_TAIL_LEN);
/* Update peripheral transport */
(*trans)->pos += payload_len + BLE_LOG_FRAME_OVERHEAD;
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
ble_log_stat_mgr_update(src_code, payload_len, false);
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* Queue trans if full */
if (BLE_LOG_TRANS_FREE_SPACE((*trans)) <= BLE_LOG_FRAME_OVERHEAD) {
ble_log_rt_queue_trans(trans);
}
}
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
void ble_log_stat_mgr_update(ble_log_src_t src_code, uint32_t len, bool lost)
{
/* Get statistic manager by source code */
ble_log_stat_mgr_t *stat_mgr = stat_mgr_ctx[src_code];
/* Update statistics */
uint32_t bytes_cnt = len + BLE_LOG_FRAME_OVERHEAD;
if (lost) {
stat_mgr->enh_stat.lost_frame_cnt++;
stat_mgr->enh_stat.lost_bytes_cnt += bytes_cnt;
} else {
stat_mgr->enh_stat.written_frame_cnt++;
stat_mgr->enh_stat.written_bytes_cnt += bytes_cnt;
}
}
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* -------------------------- */
/* INTERNAL INTERFACE */
/* -------------------------- */
bool ble_log_lbm_init(void)
{
/* Avoid double init */
if (lbm_inited) {
return true;
}
/* Initialize LBM context */
lbm_ctx = (ble_log_lbm_ctx_t *)BLE_LOG_MALLOC(sizeof(ble_log_lbm_ctx_t));
if (!lbm_ctx) {
goto exit;
}
BLE_LOG_MEMSET(lbm_ctx, 0, sizeof(ble_log_lbm_ctx_t));
/* Initialize peripheral transport for common LBMs */
ble_log_lbm_t *lbm;
for (int i = 0; i < BLE_LOG_LBM_COMMON_CNT; i++) {
lbm = &(lbm_ctx->lbm_common_pool[i]);
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
if (!ble_log_prph_trans_init(&(lbm->trans[j]),
CONFIG_BLE_LOG_LBM_TRANS_SIZE)) {
goto exit;
}
}
}
/* Initialize lock types for atomic pool */
for (int i = 0; i < BLE_LOG_LBM_ATOMIC_CNT; i++) {
lbm_ctx->atomic_pool[i].lock_type = BLE_LOG_LBM_LOCK_ATOMIC;
}
/* Initialize lock types for spin pool */
for (int i = 0; i < BLE_LOG_LBM_SPIN_MAX; i++) {
lbm_ctx->spin_pool[i].lock_type = BLE_LOG_LBM_LOCK_SPIN;
}
#if CONFIG_BLE_LOG_LL_ENABLED
for (int i = 0; i < BLE_LOG_LBM_LL_MAX; i++) {
lbm = &(lbm_ctx->lbm_ll_pool[i]);
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
if (!ble_log_prph_trans_init(&(lbm->trans[j]),
CONFIG_BLE_LOG_LBM_LL_TRANS_SIZE)) {
goto exit;
}
}
}
/* Initialize lock types for LL pool */
for (int i = 0; i < BLE_LOG_LBM_LL_MAX; i++) {
lbm_ctx->lbm_ll_pool[i].lock_type = BLE_LOG_LBM_LOCK_NONE;
}
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
/* Initialize statistic manager context */
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
stat_mgr_ctx[i] = (ble_log_stat_mgr_t *)BLE_LOG_MALLOC(sizeof(ble_log_stat_mgr_t));
if (!stat_mgr_ctx[i]) {
goto exit;
}
BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t));
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT;
stat_mgr_ctx[i]->enh_stat.src_code = i;
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
}
/* Initialization done */
lbm_ref_count = 0;
lbm_inited = true;
lbm_enabled = false;
return true;
exit:
ble_log_lbm_deinit();
return false;
}
void ble_log_lbm_deinit(void)
{
/* Set inited flag to false to prevent new references */
lbm_inited = false;
lbm_enabled = false;
/* Disable module and wait for all references to be released */
uint32_t time_waited = 0;
while (lbm_ref_count > 0) {
vTaskDelay(pdMS_TO_TICKS(1));
BLE_LOG_ASSERT(time_waited++ < 1000);
}
/* Release statistic manager context */
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
if (stat_mgr_ctx[i]) {
BLE_LOG_FREE(stat_mgr_ctx[i]);
stat_mgr_ctx[i] = NULL;
}
}
/* Release LBM */
if (lbm_ctx) {
/* Release peripheral transport for common pools */
ble_log_lbm_t *lbm;
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
lbm = &(lbm_ctx->lbm_pool[i]);
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
ble_log_prph_trans_deinit(&(lbm->trans[j]));
}
}
/* Release LBM context */
BLE_LOG_FREE(lbm_ctx);
lbm_ctx = NULL;
}
}
/* Note:
* The function below should be private, but when UART redirection is required,
* it would be a waste to implement get transport function again, thus
* make it available internally */
BLE_LOG_IRAM_ATTR
ble_log_prph_trans_t **ble_log_lbm_get_trans(ble_log_lbm_t *lbm, size_t log_len)
{
/* Check if available buffer can contain incoming log */
ble_log_prph_trans_t **trans;
for (int i = 0; i < BLE_LOG_TRANS_PING_PONG_BUF_CNT; i++) {
trans = &(lbm->trans[lbm->trans_idx]);
if (!(*trans)->prph_owned) {
/* Return if there's enough free space in current transport */
if (BLE_LOG_TRANS_FREE_SPACE((*trans)) >= (log_len + BLE_LOG_FRAME_OVERHEAD)) {
return trans;
}
/* Queue transport if there's insufficient free space */
if ((*trans)->pos) {
ble_log_rt_queue_trans(trans);
}
}
/* Current transport unavailable, switch to the other */
lbm->trans_idx = !lbm->trans_idx;
}
/* Both ping-pong buffers are unavailable */
return NULL;
}
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
void ble_log_write_enh_stat(void)
{
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
if (!lbm_enabled) {
goto deref;
}
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
ble_log_enh_stat_t *enh_stat = &(stat_mgr_ctx[i]->enh_stat);
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)enh_stat, sizeof(ble_log_enh_stat_t));
}
deref:
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
}
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* ------------------------ */
/* PUBLIC INTERFACE */
/* ------------------------ */
bool ble_log_enable(bool enable)
{
if (!lbm_inited) {
return false;
}
lbm_enabled = enable;
return true;
}
void ble_log_flush(void)
{
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
if (!lbm_inited) {
goto deref;
}
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
/* Write enhanced statistics before module disable */
ble_log_write_enh_stat();
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* Write BLE Log flush log */
ble_log_info_t ble_log_info = {
.int_src_code = BLE_LOG_INT_SRC_FLUSH,
.version = BLE_LOG_VERSION,
};
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
/* Disable module and wait for all other references to release */
bool lbm_enabled_copy = lbm_enabled;
lbm_enabled = false;
uint32_t time_waited = 0;
while (lbm_ref_count > 1) {
vTaskDelay(pdMS_TO_TICKS(1));
BLE_LOG_ASSERT(time_waited++ < 1000);
}
/* Queue transports with logs */
ble_log_lbm_t *lbm;
ble_log_prph_trans_t **trans;
/* Flush pools */
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
lbm = &(lbm_ctx->lbm_pool[i]);
int trans_idx = lbm->trans_idx;
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
trans = &(lbm->trans[trans_idx]);
if (!(*trans)->prph_owned && (*trans)->pos) {
ble_log_rt_queue_trans(trans);
}
trans_idx = !trans_idx;
}
}
/* Wait for transportation to finish */
time_waited = 0;
bool in_progress;
do {
in_progress = false;
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
lbm = &(lbm_ctx->lbm_pool[i]);
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
trans = &(lbm->trans[j]);
in_progress |= (*trans)->prph_owned;
}
}
if (in_progress) {
vTaskDelay(pdMS_TO_TICKS(1));
BLE_LOG_ASSERT(time_waited++ < 1000);
}
} while (in_progress);
/* Reset statistics manager after all operations complete */
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t));
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
/* Reinitialize enhanced statistics fields */
stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT;
stat_mgr_ctx[i]->enh_stat.src_code = i;
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
}
/* Resume enable status */
lbm_enabled = lbm_enabled_copy;
deref:
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
}
bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len)
{
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
size_t payload_len = len + sizeof(uint32_t);
if (!lbm_enabled) {
goto exit;
}
/* Get transport */
ble_log_lbm_t *lbm = ble_log_lbm_acquire();
ble_log_prph_trans_t **trans = ble_log_lbm_get_trans(lbm, payload_len);
if (!trans) {
ble_log_lbm_release(lbm);
goto exit;
}
/* Write transport */
uint32_t os_ts = pdTICKS_TO_MS(BLE_LOG_IN_ISR()?
xTaskGetTickCountFromISR():
xTaskGetTickCount());
ble_log_lbm_write_trans(trans, src_code, (const uint8_t *)&os_ts,
sizeof(uint32_t), addr, len);
/* Release */
ble_log_lbm_release(lbm);
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
return true;
exit:
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
if (lbm_inited) {
ble_log_stat_mgr_update(src_code, payload_len, true);
}
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
return false;
}
#if CONFIG_BLE_LOG_LL_ENABLED
BLE_LOG_IRAM_ATTR
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
uint32_t len_append, const uint8_t *addr_append, uint32_t flag)
{
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
size_t payload_len = len + len_append;
/* Source code shall be determined before LBM enable status check */
ble_log_src_t src_code;
bool use_ll_task = false;
if (flag & BIT(BLE_LOG_LL_FLAG_ISR)) {
src_code = BLE_LOG_SRC_LL_ISR;
} else if (flag & BIT(BLE_LOG_LL_FLAG_HCI)) {
src_code = BLE_LOG_SRC_LL_HCI;
} else if (flag & BIT(BLE_LOG_LL_FLAG_HCI_UPSTREAM)) {
src_code = BLE_LOG_SRC_HCI;
} else {
src_code = BLE_LOG_SRC_LL_TASK;
use_ll_task = true;
}
if (!lbm_enabled) {
goto exit;
}
/* Determine LBM by flag */
ble_log_lbm_t *lbm;
if (BLE_LOG_IN_ISR()) {
/* Reuse common LBM acquire logic */
lbm = ble_log_lbm_acquire();
} else {
lbm = (use_ll_task)? &(lbm_ctx->lbm_ll_task): &(lbm_ctx->lbm_ll_hci);
}
/* Get transport */
ble_log_prph_trans_t **trans = ble_log_lbm_get_trans(lbm, payload_len);
if (!trans) {
ble_log_lbm_release(lbm);
goto exit;
}
/* Write transport */
ble_log_lbm_write_trans(trans, src_code, addr, len, addr_append, len_append);
ble_log_lbm_release(lbm);
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
return;
exit:
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
if (lbm_inited) {
ble_log_stat_mgr_update(src_code, payload_len, true);
}
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
return;
}
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
void ble_log_dump_to_console(void)
{
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
if (!lbm_inited) {
goto deref;
}
int trans_idx;
ble_log_lbm_t *lbm;
ble_log_prph_trans_t *trans;
BLE_LOG_ENTER_CRITICAL();
BLE_LOG_CONSOLE("[BLE_LOG_DUMP_START:\n");
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
lbm = &(lbm_ctx->lbm_pool[i]);
trans_idx = lbm->trans_idx;
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
trans = lbm->trans[trans_idx];
BLE_LOG_FEED_WDT();
for (int k = 0; k < trans->size; k++) {
BLE_LOG_CONSOLE("%02x ", trans->buf[k]);
if (!(k & 0xFF)) {
BLE_LOG_FEED_WDT();
}
}
trans_idx = !trans_idx;
}
}
BLE_LOG_CONSOLE("\n:BLE_LOG_DUMP_END]\n\n");
BLE_LOG_EXIT_CRITICAL();
deref:
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
return;
}

View File

@@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------- */
/* BLE Log - Runtime */
/* ----------------- */
/* INCLUDE */
#include "ble_log.h"
#include "ble_log_rt.h"
#include "ble_log_lbm.h"
/* VARIABLE */
BLE_LOG_STATIC bool rt_inited = false;
BLE_LOG_STATIC TaskHandle_t rt_task_handle = NULL;
BLE_LOG_STATIC QueueHandle_t rt_queue_handle = NULL;
#if CONFIG_BLE_LOG_TS_ENABLED
BLE_LOG_STATIC bool rt_ts_enabled = false;
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
/* PRIVATE FUNCTION */
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void ble_log_rt_task(void *pvParameters)
{
(void)pvParameters;
ble_log_prph_trans_t *trans = NULL;
uint32_t curr_os_ts = 0;
uint32_t last_hook_os_ts = 0;
#ifndef UNIT_TEST
while (1)
#endif /* !UNIT_TEST */
{
/* CRITICAL:
* Blocking queue receive is mandatory for light sleep support */
if (xQueueReceive(rt_queue_handle, &trans, portMAX_DELAY) == pdTRUE) {
ble_log_prph_send_trans(trans);
}
/* Task hook */
curr_os_ts = pdTICKS_TO_MS(xTaskGetTickCount());
if ((curr_os_ts - last_hook_os_ts) < BLE_LOG_TASK_HOOK_TIMEOUT_MS) {
#ifndef UNIT_TEST
continue;
#else /* UNIT_TEST */
return;
#endif /* !UNIT_TEST */
}
last_hook_os_ts = curr_os_ts;
/* Write BLE Log info log */
ble_log_info_t ble_log_info = {
.int_src_code = BLE_LOG_INT_SRC_INFO,
.version = BLE_LOG_VERSION,
};
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
#if CONFIG_BLE_LOG_TS_ENABLED
if (rt_ts_enabled) {
ble_log_ts_info_t *ts_info = NULL;
ble_log_ts_info_update(&ts_info);
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)ts_info, sizeof(ble_log_ts_info_t));
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
ble_log_write_enh_stat();
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
}
}
/* INTERFACE */
bool ble_log_rt_init(void)
{
if (rt_inited) {
return true;
}
/* CRITICAL:
* Queue must be initialized before creating task */
rt_queue_handle = xQueueCreate(BLE_LOG_LBM_CNT, sizeof(ble_log_prph_trans_t *));
if (!rt_queue_handle) {
goto exit;
}
/* Initialize task */
if (xTaskCreate(ble_log_rt_task, "ble_log", BLE_LOG_TASK_STACK_SIZE, NULL,
BLE_LOG_TASK_PRIO, &rt_task_handle) != pdTRUE) {
goto exit;
}
rt_inited = true;
#if CONFIG_BLE_LOG_TS_ENABLED
rt_ts_enabled = false;
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
return true;
exit:
ble_log_rt_deinit();
return false;
}
void ble_log_rt_deinit(void)
{
rt_inited = false;
#if CONFIG_BLE_LOG_TS_ENABLED
rt_ts_enabled = false;
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
/* CRITICAL:
* Task must be deinitialized before deinitializing queue */
if (rt_task_handle) {
vTaskDelete(rt_task_handle);
rt_task_handle = NULL;
}
/* Release task queue */
if (rt_queue_handle) {
vQueueDelete(rt_queue_handle);
rt_queue_handle = NULL;
}
}
BLE_LOG_IRAM_ATTR void ble_log_rt_queue_trans(ble_log_prph_trans_t **trans)
{
(*trans)->prph_owned = true;
if (BLE_LOG_IN_ISR()) {
xQueueSendFromISR(rt_queue_handle, trans, NULL);
} else {
xQueueSend(rt_queue_handle, trans, portMAX_DELAY);
}
}
#if CONFIG_BLE_LOG_TS_ENABLED
bool ble_log_sync_enable(bool enable)
{
if (!rt_inited) {
return false;
}
rt_ts_enabled = enable;
return true;
}
#endif /* CONFIG_BLE_LOG_TS_ENABLED */

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------------------------- */
/* BLE Log - Timestamp Synchronization */
/* ----------------------------------- */
/* INCLUDE */
#include "ble_log_ts.h"
/* VARIABLE */
BLE_LOG_STATIC bool ts_inited = false;
BLE_LOG_STATIC ble_log_ts_info_t *ts_info = NULL;
/* INTERFACE */
bool ble_log_ts_init(void)
{
if (ts_inited) {
return true;
}
/* Initialize toggle IO */
gpio_config_t sync_io_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT(CONFIG_BLE_LOG_SYNC_IO_NUM),
};
if (gpio_config(&sync_io_conf) != ESP_OK) {
goto exit;
}
/* Initialize sync data */
ts_info = (ble_log_ts_info_t *)BLE_LOG_MALLOC(sizeof(ble_log_ts_info_t));
if (!ts_info) {
goto exit;
}
BLE_LOG_MEMSET(ts_info, 0, sizeof(ble_log_ts_info_t));
ts_info->int_src_code = BLE_LOG_INT_SRC_TS;
ts_inited = true;
return true;
exit:
ble_log_ts_deinit();
return false;
}
void ble_log_ts_deinit(void)
{
ts_inited = false;
/* Release sync data */
if (ts_info) {
BLE_LOG_FREE(ts_info);
ts_info = NULL;
}
/* Release toggle IO */
gpio_reset_pin(CONFIG_BLE_LOG_SYNC_IO_NUM);
}
void ble_log_ts_info_update(ble_log_ts_info_t **info)
{
BLE_LOG_ENTER_CRITICAL();
ts_info->io_level = !ts_info->io_level;
gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, ts_info->io_level);
ts_info->lc_ts = BLE_LOG_GET_LC_TS;
ts_info->esp_ts = esp_timer_get_time();
ts_info->os_ts = pdTICKS_TO_MS(xTaskGetTickCountFromISR());
BLE_LOG_EXIT_CRITICAL();
*info = ts_info;
}

View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------- */
/* BLE Log - Utility */
/* ----------------- */
/* INCLUDE */
#include "ble_log_util.h"
/* VARIABLE */
#ifndef UNIT_TEST
portMUX_TYPE ble_log_spin_lock = portMUX_INITIALIZER_UNLOCKED;
#endif /* !UNIT_TEST */
/* INTERNAL INTERFACE */
BLE_LOG_IRAM_ATTR uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len)
{
uint32_t sum = 0;
size_t i = 0;
/* Step 1: Sum up until 4-byte aligned */
while (((uintptr_t)(data + i) & 0x3) && (i < len)) {
sum += data[i++];
}
/* Step 2: Sum up 4-byte aligned blocks */
const uint32_t *p32 = (const uint32_t *)(data + i);
size_t blocks = (len - i) / 4;
for (size_t b = 0; b < blocks; b++) {
uint32_t v = p32[b];
sum += (v & 0xFF)
+ ((v >> 8) & 0xFF)
+ ((v >> 16) & 0xFF)
+ ((v >> 24) & 0xFF);
}
i += blocks * 4;
/* Step 3: Sum up remaining bytes */
while (i < len) {
sum += data[i++];
}
return sum;
}

View File

@@ -0,0 +1,177 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_LBM_H__
#define __BLE_LOG_LBM_H__
/* --------------------------------------- */
/* BLE Log - Log Buffer Management */
/* --------------------------------------- */
/* ---------------- */
/* Includes */
/* ---------------- */
#include "ble_log_prph.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/portmacro.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_FRAME_META(src_code, sn) ((src_code & 0xFF) | (sn << 8))
/* ---------------------------------- */
/* Log Buffer Manager Defines */
/* ---------------------------------- */
typedef enum {
BLE_LOG_LBM_LOCK_NONE,
BLE_LOG_LBM_LOCK_SPIN,
BLE_LOG_LBM_LOCK_ATOMIC,
BLE_LOG_LBM_LOCK_MUTEX,
} ble_log_lbm_lock_t;
typedef struct {
int trans_idx;
ble_log_prph_trans_t *trans[BLE_LOG_TRANS_PING_PONG_BUF_CNT];
ble_log_lbm_lock_t lock_type;
union {
/* BLE_LOG_LBM_LOCK_NONE */
void *none;
/* BLE_LOG_LBM_LOCK_SPIN */
portMUX_TYPE spin_lock;
/* BLE_LOG_LBM_LOCK_ATOMIC */
volatile bool atomic_lock;
/* BLE_LOG_LBM_LOCK_MUTEX */
SemaphoreHandle_t mutex;
};
} ble_log_lbm_t;
/* --------------------------------------- */
/* Log Buffer Manager Pool Defines */
/* --------------------------------------- */
enum {
#if CONFIG_BLE_LOG_LL_ENABLED
BLE_LOG_LBM_LL_TASK,
BLE_LOG_LBM_LL_HCI,
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
BLE_LOG_LBM_LL_MAX,
};
enum {
BLE_LOG_LBM_SPIN_TASK = 0,
BLE_LOG_LBM_SPIN_ISR,
BLE_LOG_LBM_SPIN_MAX,
};
#define BLE_LOG_LBM_ATOMIC_TASK_CNT CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT
#define BLE_LOG_LBM_ATOMIC_ISR_CNT CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT
#define BLE_LOG_LBM_ATOMIC_CNT (BLE_LOG_LBM_ATOMIC_TASK_CNT +\
BLE_LOG_LBM_ATOMIC_ISR_CNT)
#define BLE_LOG_LBM_COMMON_CNT (BLE_LOG_LBM_ATOMIC_CNT + BLE_LOG_LBM_SPIN_MAX)
#define BLE_LOG_LBM_CNT (BLE_LOG_LBM_COMMON_CNT + BLE_LOG_LBM_LL_MAX)
#define BLE_LOG_TRANS_CNT (BLE_LOG_LBM_CNT * BLE_LOG_TRANS_PING_PONG_BUF_CNT)
/* ------------------------------------------ */
/* Log Buffer Manager Context Defines */
/* ------------------------------------------ */
typedef struct {
union {
ble_log_lbm_t lbm_pool[BLE_LOG_LBM_CNT];
struct {
union {
ble_log_lbm_t lbm_common_pool[BLE_LOG_LBM_COMMON_CNT];
struct {
union {
ble_log_lbm_t spin_pool[BLE_LOG_LBM_SPIN_MAX];
struct {
ble_log_lbm_t spin_task;
ble_log_lbm_t spin_isr;
};
};
union {
ble_log_lbm_t atomic_pool[BLE_LOG_LBM_ATOMIC_CNT];
struct {
ble_log_lbm_t atomic_pool_task[BLE_LOG_LBM_ATOMIC_TASK_CNT];
ble_log_lbm_t atomic_pool_isr[BLE_LOG_LBM_ATOMIC_ISR_CNT];
};
};
};
};
union {
ble_log_lbm_t lbm_ll_pool[BLE_LOG_LBM_LL_MAX];
#if CONFIG_BLE_LOG_LL_ENABLED
struct {
ble_log_lbm_t lbm_ll_task;
ble_log_lbm_t lbm_ll_hci;
};
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
};
};
};
} ble_log_lbm_ctx_t;
/* ---------------------------------------- */
/* Enhanced Statistics Data Defines */
/* ---------------------------------------- */
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
typedef struct {
uint8_t int_src_code;
uint8_t src_code;
uint32_t written_frame_cnt;
uint32_t lost_frame_cnt;
uint32_t written_bytes_cnt;
uint32_t lost_bytes_cnt;
} __attribute__((packed)) ble_log_enh_stat_t;
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
/* -------------------------------------- */
/* Log Statistics Manager Context */
/* -------------------------------------- */
typedef struct {
uint32_t frame_sn;
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
ble_log_enh_stat_t enh_stat;
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
} ble_log_stat_mgr_t;
#define BLE_LOG_GET_FRAME_SN(VAR) __atomic_fetch_add(VAR, 1, __ATOMIC_RELAXED)
/* -------------------------- */
/* Link Layer Defines */
/* -------------------------- */
#if CONFIG_BLE_LOG_LL_ENABLED
enum {
BLE_LOG_LL_FLAG_CONTINUE = 0,
BLE_LOG_LL_FLAG_END,
BLE_LOG_LL_FLAG_TASK,
BLE_LOG_LL_FLAG_ISR,
BLE_LOG_LL_FLAG_HCI,
BLE_LOG_LL_FLAG_RAW,
BLE_LOG_LL_FLAG_HCI_UPSTREAM,
};
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
/* --------------------------- */
/* Internal Interfaces */
/* --------------------------- */
bool ble_log_lbm_init(void);
void ble_log_lbm_deinit(void);
ble_log_prph_trans_t **ble_log_lbm_get_trans(ble_log_lbm_t *lbm, size_t log_len);
void ble_log_lbm_enable(bool enable);
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
void ble_log_write_enh_stat(void);
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
#endif /* __BLE_LOG_LBM_H__ */

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_PRPH_H__
#define __BLE_LOG_PRPH_H__
/* ------------------------------ */
/* BLE Log - Peripheral Interface */
/* ------------------------------ */
/* INCLUDE */
#include "ble_log_util.h"
/* TYPEDEF */
typedef struct {
volatile bool prph_owned;
uint8_t *buf;
uint16_t size;
uint16_t pos;
/* Peripheral implementation specific context */
void *ctx;
} ble_log_prph_trans_t;
#define BLE_LOG_TRANS_FREE_SPACE(trans) (trans->size - trans->pos)
#define BLE_LOG_TRANS_PING_PONG_BUF_CNT (2)
/* 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);
#endif /* __BLE_LOG_PRPH_H__ */

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_RT_H__
#define __BLE_LOG_RT_H__
/* ----------------- */
/* BLE Log - Runtime */
/* ----------------- */
/* INCLUDE */
#include "ble_log_prph.h"
#include "ble_log_ts.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_task.h"
/* MACRO */
#define BLE_LOG_TASK_PRIO (ESP_TASK_PRIO_MAX - 1)
#define BLE_LOG_TASK_STACK_SIZE (1024)
#define BLE_LOG_TASK_HOOK_TIMEOUT_MS (1000)
/* INTERFACE */
bool ble_log_rt_init();
void ble_log_rt_deinit(void);
void ble_log_rt_queue_trans(ble_log_prph_trans_t **trans);
#endif /* __BLE_LOG_RT_H__ */

View File

@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_TS_H__
#define __BLE_LOG_TS_H__
/* ----------------------------------- */
/* BLE Log - Timestamp Synchronization */
/* ----------------------------------- */
/* INCLUDE */
#include "ble_log_util.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "driver/gpio.h"
/* MACRO */
#if CONFIG_BLE_LOG_LL_ENABLED
/* ESP BLE Controller Gen 2 */
#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) ||\
defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32H21) || defined(CONFIG_IDF_TARGET_ESP32H4)
extern uint32_t r_ble_lll_timer_current_tick_get(void);
#define BLE_LOG_GET_LC_TS r_ble_lll_timer_current_tick_get()
/* ESP BLE Controller Gen 1 */
#elif defined(CONFIG_IDF_TARGET_ESP32C2)
extern uint32_t r_os_cputime_get32(void);
#define BLE_LOG_GET_LC_TS r_os_cputime_get32()
/* Legacy BLE Controller (Wait for support) */
// #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
// extern uint32_t lld_read_clock_us(void);
// #define BLE_LOG_GET_LC_TS lld_read_clock_us()
#else /* Other targets */
#define BLE_LOG_GET_LC_TS 0
#endif /* BLE targets */
#else /* !CONFIG_BLE_LOG_LL_ENABLED */
#define BLE_LOG_GET_LC_TS 0
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
/* TYPEDEF */
typedef struct {
uint8_t int_src_code;
uint8_t io_level;
uint32_t lc_ts;
uint32_t esp_ts;
uint32_t os_ts;
} __attribute__((packed)) ble_log_ts_info_t;
/* INTERFACE */
bool ble_log_ts_init(void);
void ble_log_ts_deinit(void);
void ble_log_ts_info_update(ble_log_ts_info_t **ts_info);
#endif /* __BLE_LOG_TS_H__ */

View File

@@ -0,0 +1,162 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_UTIL_H__
#define __BLE_LOG_UTIL_H__
/* ----------------- */
/* BLE Log - Utility */
/* ----------------- */
/* INCLUDE */
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include "esp_bit_defs.h"
#ifndef UNIT_TEST
#include "freertos/portmacro.h"
#include "esp_heap_caps.h"
#include "esp_rom_serial_output.h"
#endif /* !UNIT_TEST */
/* MACRO */
/* Unit test */
#ifndef UNIT_TEST
/* 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)
/* Specifier */
#define BLE_LOG_STATIC static
#define BLE_LOG_INLINE inline
/* Section */
#define BLE_LOG_IRAM_ATTR IRAM_ATTR
/* Memory operation */
#define BLE_LOG_MEM_CAP (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA)
#define BLE_LOG_MALLOC(size) heap_caps_malloc(size, BLE_LOG_MEM_CAP)
#define BLE_LOG_FREE(ptr) heap_caps_free(ptr)
#define BLE_LOG_MEMCPY(dst, src, len) memcpy(dst, src, len)
#define BLE_LOG_MEMSET(ptr, value, len) memset(ptr, value, len)
/* Critical section wrapper */
#ifndef CONFIG_BLE_LOG_LL_ENABLED
extern portMUX_TYPE ble_log_spin_lock;
#define BLE_LOG_ENTER_CRITICAL() portENTER_CRITICAL_SAFE(&ble_log_spin_lock);
#define BLE_LOG_EXIT_CRITICAL() portEXIT_CRITICAL_SAFE(&ble_log_spin_lock);
#else /* CONFIG_BLE_LOG_LL_ENABLED */
/* Note
* It's mandatory to use the same spin lock with Link Layer in multi-core system */
extern uint32_t npl_freertos_hw_enter_critical(void);
extern void npl_freertos_hw_exit_critical(uint32_t ctx);
#define BLE_LOG_ENTER_CRITICAL() npl_freertos_hw_enter_critical()
#define BLE_LOG_EXIT_CRITICAL() npl_freertos_hw_exit_critical(0)
#endif /* !CONFIG_BLE_LOG_LL_ENABLED */
#define BLE_LOG_ACQUIRE_SPIN_LOCK(spin_lock) portENTER_CRITICAL_SAFE(spin_lock)
#define BLE_LOG_RELEASE_SPIN_LOCK(spin_lock) portEXIT_CRITICAL_SAFE(spin_lock)
#define BLE_LOG_IN_ISR() xPortInIsrContext()
#define BLE_LOG_CONSOLE esp_rom_printf
#define BLE_LOG_ASSERT(expr) assert(expr)
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
);
}
BLE_LOG_IRAM_ATTR static inline
void ble_log_cas_release(volatile bool *cas_lock)
{
__atomic_store_n(cas_lock, false, __ATOMIC_RELEASE);
}
#else /* UNIT_TEST */
/* Reference counting macros */
#define BLE_LOG_REF_COUNT_ACQUIRE(VAR) (*VAR)++
#define BLE_LOG_REF_COUNT_RELEASE(VAR) (*VAR)--
/* Specifier*/
#define BLE_LOG_STATIC
#define BLE_LOG_INLINE
/* Section */
#define BLE_LOG_IRAM_ATTR
/* Memory operation */
void *mocked_malloc(size_t size);
void mocked_free(void *ptr);
void mocked_memcpy(void *dst, const void *src, size_t len);
void mocked_memset(void *ptr, int value, size_t len);
#define BLE_LOG_MALLOC(size) mocked_malloc(size)
#define BLE_LOG_FREE(ptr) mocked_free(ptr)
#define BLE_LOG_MEMCPY(dst, src, len) mocked_memcpy(dst, src, len)
#define BLE_LOG_MEMSET(ptr, value, len) mocked_memset(ptr, value, len)
/* Critical section wrapper */
void mocked_enter_critical(void);
void mocked_exit_critical(void);
#define BLE_LOG_ENTER_CRITICAL() mocked_enter_critical()
#define BLE_LOG_EXIT_CRITICAL() mocked_exit_critical()
/* FreeRTOS API wrapper */
bool mocked_in_isr(void);
#define BLE_LOG_IN_ISR() mocked_in_isr()
/* Spin lock wrapper */
void mocked_acquire_spin_lock(void *spin_lock);
void mocked_release_spin_lock(void *spin_lock);
#define BLE_LOG_ACQUIRE_SPIN_LOCK(spin_lock) mocked_acquire_spin_lock(spin_lock)
#define BLE_LOG_RELEASE_SPIN_LOCK(spin_lock) mocked_release_spin_lock(spin_lock)
/* Printf wrapper */
void mocked_printf(const char *fmt, ...);
#define BLE_LOG_CONSOLE mocked_printf
/* Assert wrapper */
void mocked_assert(bool expr);
#define BLE_LOG_ASSERT(expr) mocked_assert(expr)
#define BLE_LOG_FEED_WDT()
bool ble_log_cas_acquire(volatile bool *cas_lock);
void ble_log_cas_release(volatile bool *cas_lock);
#endif /* UNIT_TEST */
#define BLE_LOG_VERSION (2)
/* TYPEDEF */
typedef enum {
BLE_LOG_INT_SRC_INIT_DONE,
BLE_LOG_INT_SRC_TS,
BLE_LOG_INT_SRC_ENH_STAT,
BLE_LOG_INT_SRC_INFO,
BLE_LOG_INT_SRC_FLUSH,
BLE_LOG_INT_SRC_MAX,
} ble_log_int_src_t;
typedef struct {
uint8_t int_src_code;
uint8_t version;
} __attribute__((packed)) ble_log_info_t;
/* INTERFACE */
uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len);
#endif /* __BLE_LOG_UTIL_H__ */

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_PRPH_DUMMY_H__
#define __BLE_LOG_PRPH_DUMMY_H__
/* ----------------------------------------------- */
/* BLE Log - Peripheral-specific Transport - Dummy */
/* ----------------------------------------------- */
/* INCLUDE */
#include "ble_log_prph.h"
/* TYPEDEF */
typedef struct {
uint8_t *trans_buf;
} ble_log_prph_trans_ctx_t;
#endif /* __BLE_LOG_PRPH_DUMMY_H__ */

View File

@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_PRPH_SPI_MASTER_DMA_H__
#define __BLE_LOG_PRPH_SPI_MASTER_DMA_H__
/* ----------------------------------------------- */
/* BLE Log - Peripheral Interface - SPI Master DMA */
/* ----------------------------------------------- */
/* INCLUDE */
#include "ble_log_prph.h"
#include <string.h>
#include "driver/spi_master.h"
/* TYPEDEF */
typedef spi_transaction_t ble_log_prph_trans_ctx_t;
#endif /* __BLE_LOG_PRPH_SPI_MASTER_DMA_H__ */

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BLE_LOG_PRPH_UART_DMA_H__
#define __BLE_LOG_PRPH_UART_DMA_H__
/* ----------------------------------------- */
/* BLE Log - Peripheral Interface - UART DMA */
/* ----------------------------------------- */
/* INCLUDE */
#include "ble_log_prph.h"
#include "driver/uart.h"
#include "driver/uhci.h"
/* MACRO */
#if CONFIG_BLE_LOG_PRPH_UART_DMA_PORT == UART_NUM_0
#define BLE_LOG_PRPH_UART_DMA_REDIR (1)
#else
#define BLE_LOG_PRPH_UART_DMA_REDIR (0)
#endif /* CONFIG_BLE_LOG_PRPH_UART_DMA_PORT == UART_NUM_0 */
/* TYPEDEF */
typedef struct {
ble_log_prph_trans_t *trans;
uint8_t trans_buf[0];
} ble_log_prph_trans_ctx_t;
#endif /* __BLE_LOG_PRPH_UART_DMA_H__ */

View File

@@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------------------------------------- */
/* BLE Log - Peripheral-specific Transport - Dummy */
/* ----------------------------------------------- */
/* INCLUDE */
#include "ble_log_prph_dummy.h"
/* INTERFACE */
bool ble_log_prph_init(size_t trans_cnt)
{
(void)trans_cnt;
return true;
}
void ble_log_prph_deinit(void)
{
}
bool ble_log_prph_trans_init(ble_log_prph_trans_t **trans, size_t trans_size)
{
/* Validate inputs */
if (!trans || !trans_size) {
return false;
}
/* Initialize peripheral transport data */
*trans = (ble_log_prph_trans_t *)BLE_LOG_MALLOC(sizeof(ble_log_prph_trans_t));
if (!(*trans)) {
goto exit;
}
BLE_LOG_MEMSET(*trans, 0, sizeof(ble_log_prph_trans_t));
(*trans)->size = trans_size;
/* Initialize peripheral-specific transport context */
ble_log_prph_trans_ctx_t *dummy_trans_ctx = (ble_log_prph_trans_ctx_t *)BLE_LOG_MALLOC(sizeof(ble_log_prph_trans_ctx_t));
if (!dummy_trans_ctx) {
goto exit;
}
BLE_LOG_MEMSET(dummy_trans_ctx, 0, sizeof(ble_log_prph_trans_ctx_t));
(*trans)->ctx = (void *)dummy_trans_ctx;
/* Initialize log buffer */
(*trans)->buf = (uint8_t *)BLE_LOG_MALLOC(trans_size);
if (!(*trans)->buf) {
goto exit;
}
BLE_LOG_MEMSET((*trans)->buf, 0, trans_size);
dummy_trans_ctx->trans_buf = (*trans)->buf;
return true;
exit:
ble_log_prph_trans_deinit(trans);
return false;
}
void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans)
{
/* Validate inputs */
if (!trans || !(*trans)) {
return;
}
/* Release log buffer */
if ((*trans)->buf) {
BLE_LOG_FREE((*trans)->buf);
}
/* Release peripheral-specific transport context */
if ((*trans)->ctx) {
BLE_LOG_FREE((*trans)->ctx);
}
/* Release peripheral transport data */
BLE_LOG_FREE(*trans);
*trans = NULL;
}
void ble_log_prph_send_trans(ble_log_prph_trans_t *trans)
{
(void)trans;
}

View File

@@ -0,0 +1,184 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------------------------------------- */
/* BLE Log - Peripheral Interface - SPI Master DMA */
/* ----------------------------------------------- */
/* INCLUDE */
#include "ble_log_prph_spi_master_dma.h"
#include "esp_timer.h"
/* MACRO */
#define BLE_LOG_SPI_BUS SPI2_HOST
#define BLE_LOG_SPI_MAX_TRANSFER_SIZE (10240)
#define BLE_LOG_SPI_TRANS_ITVL_MIN_US (30)
/* VARIABLE */
BLE_LOG_STATIC bool prph_inited = false;
BLE_LOG_STATIC spi_device_handle_t dev_handle = NULL;
BLE_LOG_STATIC uint32_t last_tx_done_ts = 0;
/* PRIVATE FUNCTION DECLARATION */
BLE_LOG_STATIC void spi_master_dma_tx_done_cb(spi_transaction_t *spi_trans);
BLE_LOG_STATIC void spi_master_dma_pre_tx_cb(spi_transaction_t *spi_trans);
/* PRIVATE FUNCTION */
BLE_LOG_IRAM_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();
/* Recycle transport */
ble_log_prph_trans_t *trans = (ble_log_prph_trans_t *)(spi_trans->user);
trans->pos = 0;
trans->prph_owned = false;
}
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void spi_master_dma_pre_tx_cb(spi_transaction_t *spi_trans)
{
/* SPI slave performance issue workaround */
while ((esp_timer_get_time() - last_tx_done_ts) < BLE_LOG_SPI_TRANS_ITVL_MIN_US) {}
}
/* INTERFACE */
bool ble_log_prph_init(size_t trans_cnt)
{
/* Avoid double init */
if (prph_inited) {
return true;
}
/* SPI master initialization */
spi_bus_config_t bus_config = {
.miso_io_num = -1,
.mosi_io_num = CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA_MOSI_IO_NUM,
.sclk_io_num = CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA_SCLK_IO_NUM,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = BLE_LOG_SPI_MAX_TRANSFER_SIZE,
#if CONFIG_SPI_MASTER_ISR_IN_IRAM
.intr_flags = ESP_INTR_FLAG_IRAM
#endif // CONFIG_SPI_MASTER_ISR_IN_IRAM
};
if (spi_bus_initialize(BLE_LOG_SPI_BUS, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) {
goto exit;
}
spi_device_interface_config_t dev_config = {
.clock_speed_hz = SPI_MASTER_FREQ_20M,
.mode = 0,
.spics_io_num = CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA_CS_IO_NUM,
.queue_size = trans_cnt,
.post_cb = spi_master_dma_tx_done_cb,
.pre_cb = spi_master_dma_pre_tx_cb,
.flags = SPI_DEVICE_NO_RETURN_RESULT
};
if (spi_bus_add_device(BLE_LOG_SPI_BUS, &dev_config, &dev_handle) != ESP_OK) {
goto exit;
}
/* Initialization done */
prph_inited = true;
return true;
exit:
ble_log_prph_deinit();
return false;
}
void ble_log_prph_deinit(void)
{
prph_inited = false;
if (dev_handle) {
/* Drain all queued transactions */
if (spi_device_acquire_bus(dev_handle, portMAX_DELAY) == ESP_OK) {
spi_device_release_bus(dev_handle);
spi_bus_remove_device(dev_handle);
dev_handle = NULL;
}
}
/* Note: We don't care if the bus has been inited or not */
spi_bus_free(BLE_LOG_SPI_BUS);
}
bool ble_log_prph_trans_init(ble_log_prph_trans_t **trans, size_t trans_size)
{
/* Validate inputs */
if (!trans || !trans_size) {
return false;
}
/* Initialize peripheral transport data */
*trans = (ble_log_prph_trans_t *)BLE_LOG_MALLOC(sizeof(ble_log_prph_trans_t));
if (!(*trans)) {
goto exit;
}
BLE_LOG_MEMSET(*trans, 0, sizeof(ble_log_prph_trans_t));
(*trans)->size = trans_size;
/* Initialize peripheral-specific transport context */
ble_log_prph_trans_ctx_t *spi_trans_ctx = (ble_log_prph_trans_ctx_t *)BLE_LOG_MALLOC(sizeof(ble_log_prph_trans_ctx_t));
if (!spi_trans_ctx) {
goto exit;
}
BLE_LOG_MEMSET(spi_trans_ctx, 0, sizeof(ble_log_prph_trans_ctx_t));
spi_trans_ctx->user = (void *)(*trans);
(*trans)->ctx = (void *)spi_trans_ctx;
/* Initialize log buffer */
(*trans)->buf = (uint8_t *)BLE_LOG_MALLOC(trans_size);
if (!(*trans)->buf) {
goto exit;
}
BLE_LOG_MEMSET((*trans)->buf, 0, trans_size);
spi_trans_ctx->tx_buffer = (const void *)(*trans)->buf;
return true;
exit:
ble_log_prph_trans_deinit(trans);
return false;
}
void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans)
{
/* Validate inputs */
if (!trans || !(*trans)) {
return;
}
/* Release log buffer */
if ((*trans)->buf) {
BLE_LOG_FREE((*trans)->buf);
}
/* Release peripheral-specific transport context */
if ((*trans)->ctx) {
BLE_LOG_FREE((*trans)->ctx);
}
/* Release peripheral transport data */
BLE_LOG_FREE(*trans);
*trans = NULL;
}
/* CRITICAL:
* This function is designed to be called by BLE Log Runtime only,
* function call from any other submodules is not allowed */
BLE_LOG_IRAM_ATTR void ble_log_prph_send_trans(ble_log_prph_trans_t *trans)
{
spi_transaction_t *spi_trans = (spi_transaction_t *)trans->ctx;
/* CRITICAL:
* Bytes to bits length conversion is required for tx, and rxlength must be
* cleared regardless of whether it is used for rx as per SPI master driver */
spi_trans->length = (trans->pos << 3);
spi_trans->rxlength = 0;
if (spi_device_queue_trans(dev_handle, spi_trans, 0) != ESP_OK) {
trans->prph_owned = false;
}
}

View File

@@ -0,0 +1,331 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ----------------------------------------- */
/* BLE Log - Peripheral Interface - UART DMA */
/* ----------------------------------------- */
/* INCLUDE */
#include "ble_log_prph_uart_dma.h"
#if BLE_LOG_PRPH_UART_DMA_REDIR
#include "ble_log.h"
#include "ble_log_rt.h"
#include "ble_log_lbm.h"
#include "esp_timer.h"
#include "driver/uart.h"
#include "driver/uart_vfs.h"
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
/* MACRO */
#define BLE_LOG_UART_MAX_TRANSFER_SIZE (10240)
#define BLE_LOG_UART_RX_BUF_SIZE (32)
#define BLE_LOG_UART_DMA_BURST_SIZE (32)
#if BLE_LOG_PRPH_UART_DMA_REDIR
#define BLE_LOG_UART_REDIR_BUF_SIZE (512)
#define BLE_LOG_UART_REDIR_FLUSH_TIMEOUT (100)
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
/* VARIABLE */
BLE_LOG_STATIC 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 uint32_t redir_last_write_ts = 0;
BLE_LOG_STATIC esp_timer_handle_t redir_flush_timer = NULL;
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
/* PRIVATE FUNCTION DECLARATION */
BLE_LOG_STATIC bool uart_dma_tx_done_cb(
uhci_controller_handle_t uhci_ctrl, const uhci_tx_done_event_data_t *edata, void *user_ctx);
/* PRIVATE FUNCTION */
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC bool uart_dma_tx_done_cb(
uhci_controller_handle_t uhci_ctrl, const uhci_tx_done_event_data_t *edata, void *user_ctx)
{
/* Unused arguments */
(void)uhci_ctrl;
(void)user_ctx;
/* 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)
);
ble_log_prph_trans_t *trans = uart_trans_ctx->trans;
trans->pos = 0;
trans->prph_owned = false;
return true;
}
#if BLE_LOG_PRPH_UART_DMA_REDIR
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void esp_timer_cb_flush_log(void)
{
uint32_t os_ts = pdTICKS_TO_MS(xTaskGetTickCount());
if ((os_ts - redir_last_write_ts) > BLE_LOG_UART_REDIR_FLUSH_TIMEOUT) {
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
int trans_idx = redir_lbm->trans_idx;
for (int i = 0; i < BLE_LOG_TRANS_PING_PONG_BUF_CNT; i++) {
ble_log_prph_trans_t **trans = &(redir_lbm->trans[trans_idx]);
if (!(*trans)->prph_owned && (*trans)->pos) {
ble_log_rt_queue_trans(trans);
}
trans_idx = !trans_idx;
}
xSemaphoreGive(redir_lbm->mutex);
}
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
/* INTERFACE */
bool ble_log_prph_init(size_t trans_cnt)
{
/* Avoid double init */
if (prph_inited) {
return true;
}
/* Initialize UART */
uart_config_t uart_config = {
.baud_rate = CONFIG_BLE_LOG_PRPH_UART_DMA_BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 122,
};
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)) {
goto exit;
}
/* Initialize UHCI */
uhci_controller_config_t uhci_config = {
.uart_port = CONFIG_BLE_LOG_PRPH_UART_DMA_PORT,
.tx_trans_queue_depth = trans_cnt,
.max_receive_internal_mem = BLE_LOG_UART_RX_BUF_SIZE,
.max_transmit_size = BLE_LOG_UART_MAX_TRANSFER_SIZE,
.dma_burst_size = BLE_LOG_UART_DMA_BURST_SIZE,
.rx_eof_flags.idle_eof = 1,
};
uhci_event_callbacks_t uhci_cbs = {
.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)) {
goto exit;
}
/* 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));
if (!redir_lbm) {
goto exit;
}
BLE_LOG_MEMSET(redir_lbm, 0, sizeof(ble_log_lbm_t));
/* Transport initialization */
for (int i = 0; i < BLE_LOG_TRANS_PING_PONG_BUF_CNT; i++) {
if (!ble_log_prph_trans_init(&(redir_lbm->trans[i]),
BLE_LOG_UART_REDIR_BUF_SIZE)) {
goto exit;
}
}
/* Mutex initilaization */
redir_lbm->mutex = xSemaphoreCreateMutex();
if (!redir_lbm->mutex) {
goto exit;
}
/* Initialize UART driver for redirection */
if (!uart_is_driver_installed(UART_NUM_0)) {
uart_driver_install(UART_NUM_0, BLE_LOG_UART_RX_BUF_SIZE, 0, 0, NULL, 0);
uart_driver_inited = true;
}
uart_vfs_dev_use_driver(UART_NUM_0);
/* Initialize periodic flush timer */
esp_timer_create_args_t timer_args = {
.callback = (esp_timer_cb_t)esp_timer_cb_flush_log,
.dispatch_method = ESP_TIMER_TASK,
};
if (esp_timer_create(&timer_args, &redir_flush_timer) != ESP_OK) {
goto exit;
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
prph_inited = true;
#if BLE_LOG_PRPH_UART_DMA_REDIR
esp_timer_start_periodic(redir_flush_timer, BLE_LOG_UART_REDIR_FLUSH_TIMEOUT);
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */
return true;
exit:
ble_log_prph_deinit();
return false;
}
void ble_log_prph_deinit(void)
{
prph_inited = false;
#if BLE_LOG_PRPH_UART_DMA_REDIR
/* Release flush timer */
if (redir_flush_timer) {
esp_timer_stop(redir_flush_timer);
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);
}
/* Release redirection LBM */
if (redir_lbm) {
/* Release mutex */
if (redir_lbm->mutex) {
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
xSemaphoreGive(redir_lbm->mutex);
vSemaphoreDelete(redir_lbm->mutex);
}
/* Release transport */
for (int i = 0; i < BLE_LOG_TRANS_PING_PONG_BUF_CNT; i++) {
ble_log_prph_trans_deinit(&(redir_lbm->trans[i]));
}
/* Release LBM */
BLE_LOG_FREE(redir_lbm);
redir_lbm = NULL;
}
#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;
}
}
bool ble_log_prph_trans_init(ble_log_prph_trans_t **trans, size_t trans_size)
{
/* Validate inputs */
if (!trans || !trans_size) {
return false;
}
/* Initialize peripheral transport data */
*trans = (ble_log_prph_trans_t *)BLE_LOG_MALLOC(sizeof(ble_log_prph_trans_t));
if (!(*trans)) {
goto exit;
}
BLE_LOG_MEMSET(*trans, 0, sizeof(ble_log_prph_trans_t));
(*trans)->size = trans_size;
/* Initialize peripheral-specific transport context */
size_t trans_ctx_size = sizeof(ble_log_prph_trans_ctx_t) + trans_size;
ble_log_prph_trans_ctx_t *uart_trans_ctx = (ble_log_prph_trans_ctx_t *)BLE_LOG_MALLOC(trans_ctx_size);
if (!uart_trans_ctx) {
goto exit;
}
BLE_LOG_MEMSET(uart_trans_ctx, 0, trans_ctx_size);
/* Log buffer linking */
(*trans)->ctx = (void *)uart_trans_ctx;
(*trans)->buf = (uint8_t *)uart_trans_ctx->trans_buf;
uart_trans_ctx->trans = *trans;
return true;
exit:
ble_log_prph_trans_deinit(trans);
return false;
}
void ble_log_prph_trans_deinit(ble_log_prph_trans_t **trans)
{
/* Validate inputs */
if (!trans || !(*trans)) {
return;
}
/* Release peripheral-specific transport context */
if ((*trans)->ctx) {
BLE_LOG_FREE((*trans)->ctx);
}
/* Release peripheral transport data */
BLE_LOG_FREE(*trans);
*trans = NULL;
}
/* CRITICAL:
* This function is designed to be called by BLE Log Runtime only,
* function call from any other submodules is not allowed */
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) {
trans->prph_owned = false;
}
}
/* 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)
{
xSemaphoreTake(redir_lbm->mutex, portMAX_DELAY);
ble_log_prph_trans_t **trans = ble_log_lbm_get_trans(redir_lbm, len);
if (trans) {
uint8_t *buf = (*trans)->buf + (*trans)->pos;
BLE_LOG_MEMCPY(buf, src, len);
(*trans)->pos += len;
redir_last_write_ts = pdTICKS_TO_MS(xTaskGetTickCount());
if (BLE_LOG_TRANS_FREE_SPACE((*trans)) <= BLE_LOG_FRAME_OVERHEAD) {
ble_log_rt_queue_trans(trans);
}
}
xSemaphoreGive(redir_lbm->mutex);
}
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)) {
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)) {
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)) {
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);
}
}
#endif /* BLE_LOG_PRPH_UART_DMA_REDIR */