feat(nimble): ADD BLE HCI logging support for ESP Insights

This commit is contained in:
Mayank Tyagi
2026-05-20 13:44:11 +05:30
parent 767f5e0a9b
commit 0939fbdbfd
13 changed files with 211 additions and 16 deletions
+8
View File
@@ -140,6 +140,7 @@ if(CONFIG_BT_ENABLED)
list(APPEND srcs "common/btc/core/btc_alarm.c" list(APPEND srcs "common/btc/core/btc_alarm.c"
"common/api/esp_blufi_api.c" "common/api/esp_blufi_api.c"
"common/hci_log/bt_hci_log.c" "common/hci_log/bt_hci_log.c"
"common/hci_log/bt_hci_log_insights.c"
"common/btc/core/btc_manage.c" "common/btc/core/btc_manage.c"
"common/btc/core/btc_task.c" "common/btc/core/btc_task.c"
"common/btc/profile/esp/blufi/blufi_prf.c" "common/btc/profile/esp/blufi/blufi_prf.c"
@@ -1030,6 +1031,13 @@ if(DEFINED CONFIG_BLE_LOG_PRPH_UART_DMA_PORT)
endif() endif()
endif() endif()
idf_component_get_property(bt_component_type bt COMPONENT_TYPE)
if(bt_component_type STREQUAL "LIBRARY")
idf_component_optional_requires(PRIVATE ble_insights)
else()
idf_component_optional_requires(INTERFACE ble_insights)
endif()
if(CONFIG_BLE_COMPRESSED_LOG_ENABLE) if(CONFIG_BLE_COMPRESSED_LOG_ENABLE)
if(LOG_COMPRESSION_TARGET) if(LOG_COMPRESSION_TARGET)
add_dependencies(${COMPONENT_LIB} ${LOG_COMPRESSION_TARGET}) add_dependencies(${COMPONENT_LIB} ${LOG_COMPRESSION_TARGET})
+6
View File
@@ -109,6 +109,12 @@ menu "Bluetooth"
This option is to configure the buffer size of the hci adv report cache in hci debug mode. This option is to configure the buffer size of the hci adv report cache in hci debug mode.
This is a ring buffer, the new data will overwrite the oldest data if the buffer is full. This is a ring buffer, the new data will overwrite the oldest data if the buffer is full.
config BT_HCI_LOG_INSIGHTS_ENABLE
depends on BT_HCI_LOG_DEBUG_EN
bool "Enable Insights for HCI LOGS BT Stack"
help
Enable this to allow the BT stack to send diagnostic events.
endmenu endmenu
menuconfig BLE_MESH menuconfig BLE_MESH
+10
View File
@@ -40,6 +40,16 @@ static const char s_hex_to_char_mapping[16] = {
static bt_hci_log_t g_bt_hci_log_data_ctl = {0}; static bt_hci_log_t g_bt_hci_log_data_ctl = {0};
static bt_hci_log_t g_bt_hci_log_adv_ctl = {0}; static bt_hci_log_t g_bt_hci_log_adv_ctl = {0};
uint8_t bt_hci_log_h4_type_to_data_type(uint8_t h4_type)
{
switch (h4_type) {
case 0x05:
return HCI_LOG_DATA_TYPE_ISO_DATA;
default:
return h4_type;
}
}
esp_err_t bt_hci_log_init(void) esp_err_t bt_hci_log_init(void)
{ {
uint8_t *g_bt_hci_log_data_buffer = NULL; uint8_t *g_bt_hci_log_data_buffer = NULL;
@@ -0,0 +1,90 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "esp_timer.h"
#include "bt_ble_insights.h"
#include "bt_common.h"
#include "hci_log/bt_hci_log.h"
#if (BT_HCI_LOG_INCLUDED == TRUE) && BT_HCI_INSIGHTS_INCLUDED
static uint8_t s_hci_log_seq_num = 0;
static portMUX_TYPE s_hci_log_mux = portMUX_INITIALIZER_UNLOCKED;
#define HCI_LOG_INSIGHTS_LINE_SIZE 128U
#define HCI_LOG_INSIGHTS_TS_LEN 8U
static const char *bt_hci_log_insights_label(uint8_t data_type)
{
switch (data_type) {
case HCI_LOG_DATA_TYPE_COMMAND:
return "C";
case HCI_LOG_DATA_TYPE_H2C_ACL:
return "H";
case HCI_LOG_DATA_TYPE_SCO:
return "S";
case HCI_LOG_DATA_TYPE_EVENT:
return "E";
case HCI_LOG_DATA_TYPE_ADV:
return "ADV";
case HCI_LOG_DATA_TYPE_C2H_ACL:
return "D";
case HCI_LOG_DATA_TYPE_ISO_DATA:
return "I";
default:
return NULL;
}
}
void bt_hci_log_record_insights(uint8_t data_type, const uint8_t *data, uint16_t data_len)
{
const char *label = bt_hci_log_insights_label(data_type);
char line[HCI_LOG_INSIGHTS_LINE_SIZE];
uint8_t ts_bytes[HCI_LOG_INSIGHTS_TS_LEN];
uint64_t timestamp;
uint8_t seq_num;
int offset;
if (!BT_BLE_INSIGHTS_AVAILABLE || label == NULL || data == NULL || data_len == 0) {
return;
}
portENTER_CRITICAL(&s_hci_log_mux);
seq_num = ++s_hci_log_seq_num;
portEXIT_CRITICAL(&s_hci_log_mux);
timestamp = esp_timer_get_time();
memcpy(ts_bytes, &timestamp, sizeof(ts_bytes));
offset = snprintf(line, sizeof(line), "%02x %s:", (unsigned int)seq_num, label);
if (offset < 0 || (size_t)offset >= sizeof(line) - 1) {
return;
}
for (size_t i = 0; i < sizeof(ts_bytes) && offset <= (int)sizeof(line) - 3; i++) {
offset += snprintf(&line[offset], sizeof(line) - offset, "%02x", ts_bytes[i]);
}
if (offset < 0 || (size_t)offset >= sizeof(line) - 1) {
return;
}
line[offset++] = ' ';
line[offset] = '\0';
for (uint16_t i = 0; i < data_len && offset <= (int)sizeof(line) - 3; i++) {
offset += snprintf(&line[offset], sizeof(line) - offset, "%02X", data[i]);
}
ble_insights_log(line);
}
#endif
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -102,6 +102,17 @@ esp_err_t bt_hci_log_record_hci_data(uint8_t data_type, uint8_t *data, uint16_t
*/ */
esp_err_t bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len); esp_err_t bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len);
/**
*
* @brief Convert HCI H4 packet type to HCI log data type.
*
* @param h4_type : HCI H4 packet type byte
*
* @return corresponding HCI log data type
*
*/
uint8_t bt_hci_log_h4_type_to_data_type(uint8_t h4_type);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_BLE_INSIGHTS_H__
#define __BT_BLE_INSIGHTS_H__
#if __has_include("ble_insights.h")
#include "ble_insights.h"
#define BT_BLE_INSIGHTS_AVAILABLE 1
#else
#define BT_BLE_INSIGHTS_AVAILABLE 0
static inline void ble_insights_log(const char *log)
{
(void)log;
}
#endif
#endif /* __BT_BLE_INSIGHTS_H__ */
+14 -3
View File
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -100,6 +100,13 @@
#define BT_HCI_LOG_INCLUDED FALSE #define BT_HCI_LOG_INCLUDED FALSE
#endif #endif
// HCI INSIGHTS LOG
#if UC_BT_HCI_LOG_INSIGHTS_ENABLE
#define BT_HCI_INSIGHTS_INCLUDED UC_BT_HCI_LOG_INSIGHTS_ENABLE
#else
#define BT_HCI_INSIGHTS_INCLUDED FALSE
#endif
// HCI LOG TO SPI // HCI LOG TO SPI
#if UC_BT_BLE_LOG_SPI_OUT_HCI_ENABLED #if UC_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
#define BT_BLE_LOG_SPI_OUT_HCI_ENABLED UC_BT_BLE_LOG_SPI_OUT_HCI_ENABLED #define BT_BLE_LOG_SPI_OUT_HCI_ENABLED UC_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
@@ -117,10 +124,10 @@
#if UC_BT_HCI_LOG_DATA_BUFFER_SIZE #if UC_BT_HCI_LOG_DATA_BUFFER_SIZE
#define HCI_LOG_DATA_BUFFER_SIZE UC_BT_HCI_LOG_DATA_BUFFER_SIZE #define HCI_LOG_DATA_BUFFER_SIZE UC_BT_HCI_LOG_DATA_BUFFER_SIZE
#else #else
#define HCI_BUFFER_SIZE (5) #define HCI_LOG_DATA_BUFFER_SIZE (5)
#endif #endif
#if UC_BT_HCI_ADV_BUFFER_SIZE #if UC_BT_HCI_LOG_ADV_BUFFER_SIZE
#define HCI_LOG_ADV_BUFFER_SIZE UC_BT_HCI_LOG_ADV_BUFFER_SIZE #define HCI_LOG_ADV_BUFFER_SIZE UC_BT_HCI_LOG_ADV_BUFFER_SIZE
#else #else
#define HCI_LOG_ADV_BUFFER_SIZE (5) #define HCI_LOG_ADV_BUFFER_SIZE (5)
@@ -277,4 +284,8 @@ typedef struct {
#define BD_ADDR_LEN 6 /* Device address length */ #define BD_ADDR_LEN 6 /* Device address length */
typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */ typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */
#if (BT_HCI_LOG_INCLUDED == TRUE) && BT_HCI_INSIGHTS_INCLUDED
void bt_hci_log_record_insights(uint8_t data_type, const uint8_t *data, uint16_t data_len);
#endif
#endif /* _BT_COMMON_H_ */ #endif /* _BT_COMMON_H_ */
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -176,4 +176,12 @@
#define UC_BT_HCI_LOG_ADV_BUFFER_SIZE (5) #define UC_BT_HCI_LOG_ADV_BUFFER_SIZE (5)
#endif #endif
// HCI LOG INSIGHTS
#ifdef CONFIG_BT_HCI_LOG_INSIGHTS_ENABLE
#define UC_BT_HCI_LOG_INSIGHTS_ENABLE TRUE
#else
#define UC_BT_HCI_LOG_INSIGHTS_ENABLE FALSE
#endif
#endif /* __BT_USER_CONFIG_H__ */ #endif /* __BT_USER_CONFIG_H__ */
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -8,6 +8,7 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_bluedroid_hci.h" #include "esp_bluedroid_hci.h"
#include "common/bt_target.h" #include "common/bt_target.h"
#include "bt_common.h"
#include "hci/hci_trans_int.h" #include "hci/hci_trans_int.h"
#if (BT_CONTROLLER_INCLUDED == TRUE) #if (BT_CONTROLLER_INCLUDED == TRUE)
#include "esp_bt.h" #include "esp_bt.h"
@@ -69,7 +70,11 @@ void hci_host_send_packet(uint8_t *data, uint16_t len)
{ {
#if (BT_HCI_LOG_INCLUDED == TRUE) #if (BT_HCI_LOG_INCLUDED == TRUE)
if (data != NULL && len > 1) { if (data != NULL && len > 1) {
bt_hci_log_record_hci_data(data[0], &data[1], (uint16_t)(len - 1)); uint8_t data_type = bt_hci_log_h4_type_to_data_type(data[0]);
bt_hci_log_record_hci_data(data_type, &data[1], (uint16_t)(len - 1));
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(data_type, &data[1], (uint16_t)(len - 1));
#endif
} }
#endif #endif
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED #if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
@@ -34,6 +34,7 @@
#include "esp_bt.h" #include "esp_bt.h"
#endif #endif
#include "esp_bluedroid_hci.h" #include "esp_bluedroid_hci.h"
#include "bt_common.h"
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE) #if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
#include "l2c_int.h" #include "l2c_int.h"
@@ -601,14 +602,20 @@ void bt_record_hci_data(uint8_t *data, uint16_t len)
#endif // (BLE_50_FEATURE_SUPPORT == TRUE) #endif // (BLE_50_FEATURE_SUPPORT == TRUE)
)) { )) {
bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2); bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2);
#endif
} else { } else {
uint8_t data_type; uint8_t data_type;
if (data[0] == HCI_LOG_DATA_TYPE_ISO_DATA) { if (data[0] == DATA_TYPE_ISO) {
data_type = HCI_LOG_DATA_TYPE_ISO_DATA; data_type = HCI_LOG_DATA_TYPE_ISO_DATA;
} else { } else {
data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]); data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]);
} }
bt_hci_log_record_hci_data(data_type, &data[1], len - 1); bt_hci_log_record_hci_data(data_type, &data[1], len - 1);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(data_type, &data[1], len - 1);
#endif
} }
#endif // (BT_HCI_LOG_INCLUDED == TRUE) #endif // (BT_HCI_LOG_INCLUDED == TRUE)
} }
@@ -78,7 +78,11 @@ void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
void esp_vhci_host_send_packet_wrapper(uint8_t *data, uint16_t len) void esp_vhci_host_send_packet_wrapper(uint8_t *data, uint16_t len)
{ {
#if (BT_HCI_LOG_INCLUDED == TRUE) #if (BT_HCI_LOG_INCLUDED == TRUE)
bt_hci_log_record_hci_data(data[0], &data[1], len - 1); uint8_t data_type = bt_hci_log_h4_type_to_data_type(data[0]);
bt_hci_log_record_hci_data(data_type, &data[1], len - 1);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(data_type, &data[1], len - 1);
#endif
#endif #endif
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED #if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len); ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len);
@@ -237,18 +241,24 @@ static void dummy_controller_rcv_pkt_ready(void)
void bt_record_hci_data(uint8_t *data, uint16_t len) void bt_record_hci_data(uint8_t *data, uint16_t len)
{ {
#if (BT_HCI_LOG_INCLUDED == TRUE) #if (BT_HCI_LOG_INCLUDED == TRUE)
if ((data[0] == BLE_HCI_UART_H4_EVT) && (data[1] == BLE_HCI_EVCODE_LE_META) && ((data[3] == BLE_HCI_LE_SUBEV_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) if (len < 2) {
return;
}
if ((len >= 4) && (data[0] == BLE_HCI_UART_H4_EVT) && (data[1] == BLE_HCI_EVCODE_LE_META) && ((data[3] == BLE_HCI_LE_SUBEV_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT)
|| (data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT))) { || (data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT))) {
bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2); bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2);
#endif
} else { } else {
uint8_t data_type; uint8_t data_type;
if (data[0] == HCI_LOG_DATA_TYPE_ISO_DATA) { data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : bt_hci_log_h4_type_to_data_type(data[0]));
data_type = HCI_LOG_DATA_TYPE_ISO_DATA;
} else {
data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]);
}
bt_hci_log_record_hci_data(data_type, &data[1], len - 1); bt_hci_log_record_hci_data(data_type, &data[1], len - 1);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(data_type, &data[1], len - 1);
#endif
} }
#endif // (BT_HCI_LOG_INCLUDED == TRUE) #endif // (BT_HCI_LOG_INCLUDED == TRUE)
} }
@@ -2382,4 +2382,12 @@
#endif #endif
#endif #endif
#ifndef MYNEWT_VAL_BT_NIMBLE_INSIGHTS_ENABLE
#ifdef CONFIG_BT_NIMBLE_INSIGHTS_ENABLE
#define MYNEWT_VAL_BT_NIMBLE_INSIGHTS_ENABLE CONFIG_BT_NIMBLE_INSIGHTS_ENABLE
#else
#define MYNEWT_VAL_BT_NIMBLE_INSIGHTS_ENABLE (0)
#endif
#endif
#endif #endif