feat(ble_audio): Support log compression for ISO & LE Audio logs

This commit is contained in:
Liu Linyan
2026-05-07 15:05:57 +08:00
parent c9ce65f6c1
commit cae52c454b
56 changed files with 578 additions and 65 deletions
@@ -15,6 +15,16 @@ set(HOST_LOG_INDEX_HEADER "\"\"")
set(BLE_HOST_TAGS "")
set(BLE_HOST_TAGS_PRESERVE "")
# default config value for ble iso module
# (esp_ble_iso owns the unified LOG_* family; consumers like esp_ble_audio
# and future HID-over-ISO compile under the same BLE_ISO module so that all
# share one iso_log_index.h and one log-id counter — no per-consumer
# bookkeeping, no redefinition risk.)
set(BLE_ISO_CODE_PATH "")
set(BLE_ISO_LOG_INDEX_HEADER "\"\"")
set(BLE_ISO_TAGS "")
set(BLE_ISO_TAGS_PRESERVE "")
if(CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE)
list(APPEND LOG_COMPRESSED_MODULE "BLE_MESH")
@@ -31,6 +41,26 @@ if(CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE)
list(APPEND LOG_COMPRESSED_MODULE_CODE_PATH ${BLE_MESH_CODE_PATH})
endif()
if(CONFIG_BLE_ISO_COMPRESSED_LOG_ENABLE)
list(APPEND LOG_COMPRESSED_MODULE "BLE_ISO")
# esp_ble_audio sources share the same LOG_* macro family from
# esp_ble_iso/include/zephyr/logging/log.h; compile them under the
# single BLE_ISO module so they all hit one iso_log_index.h with one
# monotonic log-id counter. Future ISO consumers (e.g. HID-over-ISO)
# extend this list the same way — no per-consumer index header or
# Kconfig toggle.
set(BLE_ISO_CODE_PATH "esp_ble_iso" "esp_ble_audio")
set(BLE_ISO_LOG_INDEX_HEADER "iso_log_index.h")
set(BLE_ISO_LOG_SCRIPT_PATH
"${CMAKE_CURRENT_LIST_DIR}/scripts/module_scripts/ble_iso/make_iso_log_macro.py")
include(${CMAKE_CURRENT_LIST_DIR}/cmake/ble_iso_log_tags.cmake)
if(NOT EXISTS "${CMAKE_BINARY_DIR}/ble_log/include/${BLE_ISO_LOG_INDEX_HEADER}")
file(WRITE "${CMAKE_BINARY_DIR}/ble_log/include/${BLE_ISO_LOG_INDEX_HEADER}" "")
endif()
list(APPEND LOG_COMPRESSED_MODULE_CODE_PATH ${BLE_ISO_CODE_PATH})
endif()
if(CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE AND CONFIG_BT_BLUEDROID_ENABLED)
list(APPEND LOG_COMPRESSED_MODULE "BLE_HOST")
@@ -127,6 +157,12 @@ if(LOG_COMPRESSED_MODULE)
file(WRITE "${CMAKE_BINARY_DIR}/ble_log/module_info.yml")
endif()
set(YML_IN "${BT_ROOT_PATH}/common/ble_log/extension/log_compression/scripts/configs/module_info.yml.in")
# BLE_ISO has multiple code paths; rewrite CMake list ";" → YAML ", "
# into a sibling variable so BLE_ISO_CODE_PATH itself stays a CMake
# list usable by any later code that wants to iterate or append.
string(REPLACE ";" ", " BLE_ISO_CODE_PATH_YAML "${BLE_ISO_CODE_PATH}")
configure_file(${YML_IN} ${CONFIG_FILE_PATH} @ONLY)
string(REPLACE ";" "|" MODULE_CODE_PATH "${LOG_COMPRESSED_MODULE_CODE_PATH}")
@@ -689,4 +689,112 @@ if BLE_COMPRESSED_LOG_ENABLE
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
endmenu
endif
# ---------------------------------------------------------------------
# BLE ISO log compression (esp_ble_iso component)
# ---------------------------------------------------------------------
menuconfig BLE_ISO_COMPRESSED_LOG_ENABLE
bool "Enable BLE ISO log compression(Preview)"
depends on BLE_COMPRESSED_LOG_ENABLE
depends on BT_ISO
default n
help
Apply compression to ESP-BLE-ISO host shim logs (the
esp_ble_iso component) AND every IDF-source consumer that
shares the ISO LOG_* macro family — currently esp_ble_audio,
and future modules such as HID-over-ISO. All such sources
share one iso_log_index.h with one monotonic log-id counter.
Requires base BLE compression to be enabled.
Note: prebuilt libraries (e.g. libble_audio.a) emit logs via
an independent runtime callback (BLE_AUDIO_LIB) and are not
governed by this option.
Note: This library depends on additional Python packages. It
will function correctly only after these dependencies are
installed; refer to:
"components/bt/common/ble_log/log_compression/README.en.md"
for installation instructions.
If the required packages are not installed, the
log-compression mechanism will remain disabled even when this
Config is enabled.
config BLE_ISO_COMPRESSED_LOG_BUFFER_LEN
int "BLE ISO log buffer length"
depends on BLE_ISO_COMPRESSED_LOG_ENABLE
default 512
help
Maximum output length for a single log. Shared by every IDF
source compiled into the BLE_ISO compression channel
(esp_ble_iso, esp_ble_audio, and future ISO consumers).
if BLE_ISO_COMPRESSED_LOG_ENABLE
menu "Select the stack log tag to be compressed"
config BLE_ISO_STACK_ERR_LOG_COMPRESSION
bool "Compress ERROR log"
default y
help
The error log in the BLE-ISO component will be compressed
config BLE_ISO_STACK_ERR_LOG_PRESERVE
bool "Keep the original error log statement"
depends on BLE_ISO_STACK_ERR_LOG_COMPRESSION
default y
help
When this option is enabled, the log data will be output
through both the compressed log interface and the original
UART interface at the same time, meaning that the log
statements will appear on both paths. However, please note
that this dual-output approach introduces additional code
and string constants, which will increase the size of the
firmware binary file. When this option is disabled, the
logs will no longer be printed through the original UART
output path; instead, they will only be output through the
compressed log interface. As the code and strings related
to the original UART output are omitted, the size of the
firmware binary file can be effectively reduced.
config BLE_ISO_STACK_WARN_LOG_COMPRESSION
bool "Compress warn log"
default y
help
The warn log in the BLE-ISO component will be compressed.
config BLE_ISO_STACK_WARN_LOG_PRESERVE
bool "Keep the original warn log statement"
depends on BLE_ISO_STACK_WARN_LOG_COMPRESSION
default y
help
Please refer to the help information in BLE_ISO_STACK_ERR_LOG_PRESERVE.
config BLE_ISO_STACK_INFO_LOG_COMPRESSION
bool "Compress info log"
default y
help
The info log in the BLE-ISO component will be compressed.
config BLE_ISO_STACK_INFO_LOG_PRESERVE
bool "Keep the original info log statement"
depends on BLE_ISO_STACK_INFO_LOG_COMPRESSION
default n
help
Please refer to the help information in BLE_ISO_STACK_ERR_LOG_PRESERVE.
config BLE_ISO_STACK_DEBUG_LOG_COMPRESSION
bool "Compress debug log"
default y
help
The debug log in the BLE-ISO component will be compressed.
config BLE_ISO_STACK_DEBUG_LOG_PRESERVE
bool "Keep the original debug log statement"
depends on BLE_ISO_STACK_DEBUG_LOG_COMPRESSION
default n
help
Please refer to the help information in BLE_ISO_STACK_ERR_LOG_PRESERVE.
endmenu
endif
endif
@@ -50,6 +50,16 @@ INIT_BUFFER_MGMT(mesh, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
char * mesh_last_task_handle = NULL;
#endif
#if CONFIG_BLE_ISO_COMPRESSED_LOG_ENABLE
/* The BLE_ISO buffer is shared by every source compiled into the unified
* ISO channel: esp_ble_iso, esp_ble_audio (and future ISO consumers, e.g.
* HID-over-ISO), as well as the AUDIO_LIB runtime callback (prebuilt
* libble_audio.a, source code 5) — they all funnel here. */
DECLARE_BUFFERS(iso, CONFIG_BLE_ISO_COMPRESSED_LOG_BUFFER_LEN, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
INIT_BUFFER_MGMT(iso, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
char * iso_last_task_handle = NULL;
#endif
#if CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE && CONFIG_BT_BLUEDROID_ENABLED
DECLARE_BUFFERS(host, CONFIG_BLE_HOST_COMPRESSED_LOG_BUFFER_LEN, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
INIT_BUFFER_MGMT(host, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
@@ -80,6 +90,13 @@ int ble_compressed_log_cb_get(uint8_t source, ble_cp_log_buffer_mgmt_t **mgmt)
last_handle = &mesh_last_task_handle;
break;
#endif
#if CONFIG_BLE_ISO_COMPRESSED_LOG_ENABLE
case BLE_COMPRESSED_LOG_OUT_SOURCE_ISO:
case BLE_COMPRESSED_LOG_OUT_SOURCE_AUDIO_LIB:
buffer_mgmt = BUF_MGMT_NAME(iso);
last_handle = &iso_last_task_handle;
break;
#endif
#if CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE && (CONFIG_BT_BLUEDROID_ENABLED || CONFIG_BT_NIMBLE_ENABLED)
case BLE_COMPRESSED_LOG_OUT_SOURCE_HOST:
#if CONFIG_BT_BLUEDROID_ENABLED
@@ -0,0 +1,25 @@
set(_BLE_ISO_TAG_MAP
CONFIG_BLE_ISO_STACK_ERR_LOG_COMPRESSION
CONFIG_BLE_ISO_STACK_ERR_LOG_PRESERVE
LOG_ERR
CONFIG_BLE_ISO_STACK_WARN_LOG_COMPRESSION
CONFIG_BLE_ISO_STACK_WARN_LOG_PRESERVE
LOG_WRN
CONFIG_BLE_ISO_STACK_INFO_LOG_COMPRESSION
CONFIG_BLE_ISO_STACK_INFO_LOG_PRESERVE
LOG_INF
CONFIG_BLE_ISO_STACK_DEBUG_LOG_COMPRESSION
CONFIG_BLE_ISO_STACK_DEBUG_LOG_PRESERVE
LOG_DBG
)
include(${CMAKE_CURRENT_LIST_DIR}/tag_table_function.cmake)
set(BLE_ISO_TAGS "")
set(BLE_ISO_TAGS_PRESERVE "")
tag_table_to_lists(_BLE_ISO_TAG_MAP BLE_ISO_TAGS BLE_ISO_TAGS_PRESERVE)
set(BLE_ISO_TAGS "${BLE_ISO_TAGS}" PARENT_SCOPE)
set(BLE_ISO_TAGS_PRESERVE "${BLE_ISO_TAGS_PRESERVE}" PARENT_SCOPE)
@@ -10,8 +10,13 @@
#include <stdio.h>
#include <string.h>
#ifndef CONCAT
#define CONCAT(a, b) a##b
#endif
#ifndef _CONCAT
#define _CONCAT(a, b) CONCAT(a, b)
#endif
#define _0 0
#define _1 1
@@ -27,8 +32,10 @@
#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n
#define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#ifndef FOR_EACH_IDX
#define FOR_EACH_IDX(macro, name, len, ...) \
_CONCAT(_FOR_EACH_, COUNT_ARGS(__VA_ARGS__))(macro, name, len, __VA_ARGS__)
#endif
#define _FOR_EACH_0(m, n, l, ...)
#define _FOR_EACH_1(m, n, l, i1, ...) m(n, l, i1)
@@ -50,6 +57,8 @@ enum {
BLE_COMPRESSED_LOG_OUT_SOURCE_HOST,
BLE_COMPRESSED_LOG_OUT_SOURCE_MESH,
BLE_COMPRESSED_LOG_OUT_SOURCE_MESH_LIB,
BLE_COMPRESSED_LOG_OUT_SOURCE_ISO,
BLE_COMPRESSED_LOG_OUT_SOURCE_AUDIO_LIB,
};
enum {
@@ -76,6 +76,8 @@ SOURCE_ENUM_MAP = {
'BLE_HOST': 0,
'BLE_MESH': 1,
'BLE_MESH_LIB': 2,
'BLE_ISO': 3,
'BLE_AUDIO_LIB': 4,
}
# Functions that require hex formatting
@@ -18,6 +18,14 @@ log_config:
tags: [@BLE_HOST_TAGS@]
tags_with_preserve: [@BLE_HOST_TAGS_PRESERVE@]
BLE_ISO:
description: "BLE ISO (and consumers: esp_ble_audio, future HID-over-ISO)"
code_path: [@BLE_ISO_CODE_PATH_YAML@]
log_index_file: @BLE_ISO_LOG_INDEX_HEADER@
script: @BLE_ISO_LOG_SCRIPT_PATH@
tags: [@BLE_ISO_TAGS@]
tags_with_preserve: [@BLE_ISO_TAGS_PRESERVE@]
@BLE_COMPRESSED_LIB_NAME@:
description: "@BLE_COMPRESSED_LIB_DESC@"
code_path: [@BLE_COMPRESSED_LIB_CODE_DIR@]
@@ -0,0 +1,73 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
"""Macro generator shared by the BLE_ISO and BLE_AUDIO compression modules.
Both components consume the LOG_ERR / LOG_WRN / LOG_INF / LOG_DBG macros
defined in components/bt/esp_ble_iso/include/zephyr/logging/log.h and gate
output through CONFIG_BT_ISO_LOG_LEVEL with the BT_ISO_LOG_* numeric levels.
"""
import textwrap
def generate_iso_log_prefix(tag: str, print_statm: str) -> str:
"""Wrap a compressed-print statement with the matching level check."""
level = tag.split('_')[-1] # LOG_ERR -> ERR
if level == 'ERR':
log_level = 'BT_ISO_LOG_ERROR'
elif level == 'WRN':
log_level = 'BT_ISO_LOG_WARN'
elif level == 'INF':
log_level = 'BT_ISO_LOG_INFO'
elif level == 'DBG':
log_level = 'BT_ISO_LOG_DEBUG'
else:
return ''
used_log_levl = 'CONFIG_BT_ISO_LOG_LEVEL'
return f'{{do {{ if (({used_log_levl} >= {log_level})) {{ {print_statm}; }} }} while (0);}}\\\n'
def gen_header_head() -> str:
head = textwrap.dedent("""
// Compression function declarations
extern int ble_log_compressed_hex_print
(uint8_t source, uint32_t log_index, size_t args_size_cnt, ...);
extern int ble_log_compressed_hex_print_buf
(uint8_t source, uint32_t log_index, uint8_t buf_idx, const uint8_t *buf, size_t len);
""")
return head
def gen_compressed_stmt(log_index: int, module_id: int, func_name: str, fmt: str, args: list, buffer_args: list) -> str:
if len(args) == 0:
stmt = f' ble_log_compressed_hex_print({module_id}, {log_index}, 0);'
for idx, buffer_arg in enumerate(buffer_args):
stmt += '\\\n'
stmt += (
f' ble_log_compressed_hex_print_buf('
f'{module_id}, {log_index}, {idx}, '
f'(const uint8_t *){buffer_arg["buffer"]}, {buffer_arg["length"]});'
)
stmt += '\\\n'
return ' ' + generate_iso_log_prefix(func_name, stmt)
size_str = ', '.join([arg['size_type'] for arg in args])
# Strip both backslash-newline continuations and bare newlines from arg
# names so they don't leak into the generated C macro body — the same
# cleanup the NimBLE / Bluedroid generators do.
args_str = ', '.join([arg['name'] for arg in args]).replace('\\\n', '').replace('\n', '')
stmt = f' ble_log_compressed_hex_print({module_id}, {log_index}, {len(args)}, {size_str}, {args_str});'
for idx, buffer_arg in enumerate(buffer_args):
stmt += '\\\n'
stmt += (
f' ble_log_compressed_hex_print_buf('
f'{module_id}, {log_index}, {idx}, '
f'(const uint8_t *){buffer_arg["buffer"]}, {buffer_arg["length"]});'
)
stmt += '\\\n'
return ' ' + generate_iso_log_prefix(func_name, stmt)