Skip to content

Commit

Permalink
Merge branch 'feature/add_api_to_send_vendor_hci_cmd_v5.2' into 'rele…
Browse files Browse the repository at this point in the history
…ase/v5.2'

feat(bt/bluedroid): add api to send vendor hci command (backport v5.2)

See merge request espressif/esp-idf!30127
  • Loading branch information
wmy-espressif committed Apr 16, 2024
2 parents a7d981d + a43f54c commit 40d3981
Show file tree
Hide file tree
Showing 22 changed files with 775 additions and 22 deletions.
2 changes: 2 additions & 0 deletions components/bt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(common_include_dirs
common/api/include/api
common/btc/profile/esp/blufi/include
common/btc/profile/esp/include
common/hci_log/include
)

set(ble_mesh_include_dirs
Expand Down Expand Up @@ -111,6 +112,7 @@ if(CONFIG_BT_ENABLED)

list(APPEND srcs "common/btc/core/btc_alarm.c"
"common/api/esp_blufi_api.c"
"common/hci_log/bt_hci_log.c"
"common/btc/core/btc_manage.c"
"common/btc/core/btc_task.c"
"common/btc/profile/esp/blufi/blufi_prf.c"
Expand Down
25 changes: 25 additions & 0 deletions components/bt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,31 @@ menu "Bluetooth"
We cannot split the memory into 3 different regions (IRAM, BLE-IRAM, DRAM).
So this option will disable the PMP (ESP_SYSTEM_PMP_IDRAM_SPLIT)

config BT_HCI_LOG_DEBUG_EN
depends on BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED
bool "Enable Bluetooth HCI debug mode"
default n
help
This option is used to enable bluetooth debug mode, which saves the hci layer data stream.

config BT_HCI_LOG_DATA_BUFFER_SIZE
depends on BT_HCI_LOG_DEBUG_EN
int "Size of the cache used for HCI data in Bluetooth HCI debug mode (N*1024 bytes)"
range 1 100
default 5
help
This option is to configure the buffer size of the hci data steam cache in hci debug mode.
This is a ring buffer, the new data will overwrite the oldest data if the buffer is full.

config BT_HCI_LOG_ADV_BUFFER_SIZE
depends on BT_HCI_LOG_DEBUG_EN
int "Size of the cache used for adv report in Bluetooth HCI debug mode (N*1024 bytes)"
range 1 100
default 8
help
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.

endmenu

menuconfig BLE_MESH
Expand Down
334 changes: 334 additions & 0 deletions components/bt/common/hci_log/bt_hci_log.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "hci_log/bt_hci_log.h"
#include "bt_common.h"
#include "osi/mutex.h"
#include "esp_attr.h"

#if (BT_HCI_LOG_INCLUDED == TRUE)
#define BT_HCI_LOG_PRINT_TAG (1)
#define BT_HCI_LOG_DATA_BUF_SIZE (1024 * HCI_LOG_DATA_BUFFER_SIZE)
#define BT_HCI_LOG_ADV_BUF_SIZE (1024 * HCI_LOG_ADV_BUFFER_SIZE)

typedef struct {
osi_mutex_t mutex_lock;
uint64_t log_record_in;
uint64_t log_record_out;
uint64_t buf_size;
uint8_t *p_hci_log_buffer;
uint8_t index;
bool overflow;
} bt_hci_log_t;

static const char s_hex_to_char_mapping[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};

bt_hci_log_t g_bt_hci_log_data_ctl = {0};
bt_hci_log_t g_bt_hci_log_adv_ctl = {0};

esp_err_t bt_hci_log_init(void)
{
uint8_t *g_bt_hci_log_data_buffer = NULL;
uint8_t *g_bt_hci_log_adv_buffer = NULL;

g_bt_hci_log_data_buffer = malloc(BT_HCI_LOG_DATA_BUF_SIZE);
if (!g_bt_hci_log_data_buffer) {
return ESP_ERR_NO_MEM;
}
g_bt_hci_log_adv_buffer = malloc(BT_HCI_LOG_ADV_BUF_SIZE);
if (!g_bt_hci_log_adv_buffer) {
if (g_bt_hci_log_data_buffer) {
free(g_bt_hci_log_data_buffer);
g_bt_hci_log_data_buffer = NULL;
}
return ESP_ERR_NO_MEM;
}

memset(g_bt_hci_log_data_buffer, 0, BT_HCI_LOG_DATA_BUF_SIZE);
memset(g_bt_hci_log_adv_buffer, 0, BT_HCI_LOG_ADV_BUF_SIZE);

memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t));
g_bt_hci_log_data_ctl.buf_size = BT_HCI_LOG_DATA_BUF_SIZE;
g_bt_hci_log_data_ctl.p_hci_log_buffer = g_bt_hci_log_data_buffer;

memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t));
g_bt_hci_log_adv_ctl.buf_size = BT_HCI_LOG_ADV_BUF_SIZE;
g_bt_hci_log_adv_ctl.p_hci_log_buffer = g_bt_hci_log_adv_buffer;

osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock);
osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock);

return ESP_OK;
}

esp_err_t bt_hci_log_deinit(void)
{
if (g_bt_hci_log_data_ctl.p_hci_log_buffer) {
free(g_bt_hci_log_data_ctl.p_hci_log_buffer);
g_bt_hci_log_data_ctl.p_hci_log_buffer = NULL;
}

if (g_bt_hci_log_adv_ctl.p_hci_log_buffer) {
free(g_bt_hci_log_adv_ctl.p_hci_log_buffer);
g_bt_hci_log_adv_ctl.p_hci_log_buffer = NULL;
}

osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock);
osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock);

memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t));
memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t));

return ESP_OK;
}

#if (BT_HCI_LOG_PRINT_TAG)
static char IRAM_ATTR *bt_data_type_to_str(uint8_t data_type)
{
char *tag = NULL;
switch (data_type)
{
case HCI_LOG_DATA_TYPE_COMMAND:
// hci cmd data
tag = "CMD";
break;
case HCI_LOG_DATA_TYPE_H2C_ACL:
// host to controller hci acl data
tag = "HAL";
break;
case HCI_LOG_DATA_TYPE_SCO:
// hci sco data
tag = "SCO";
break;
case HCI_LOG_DATA_TYPE_EVENT:
// hci event
tag = "EVT";
break;
case HCI_LOG_DATA_TYPE_ADV:
// controller adv report data
tag = "ADV";
break;
case HCI_LOG_DATA_TYPE_C2H_ACL:
// controller to host hci acl data
tag = "CAL";
break;
case HCI_LOG_DATA_TYPE_SELF_DEFINE:
// self-defining data
tag = "ST";
break;
default:
// unknown data type
tag = "UK";
break;
}

return tag;
}
#endif

void bt_hci_log_record_hex(bt_hci_log_t *p_hci_log_ctl, uint8_t *hex, uint8_t hex_len)
{
uint8_t hci_log_char;
uint8_t *g_hci_log_buffer;

g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;

while (hex_len--)
{
hci_log_char = ((*hex) >> 4);

g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char];

if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}
if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}

hci_log_char = ((*hex) & 0x0f);

g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char];

if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}

if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}

g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ' ';

if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}
if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}

++ hex;
}
}

void bt_hci_log_record_string(bt_hci_log_t *p_hci_log_ctl, char *string)
{
uint8_t *g_hci_log_buffer;

g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;

while (*string != '\0') {
g_hci_log_buffer[p_hci_log_ctl->log_record_in] = *string;
++string;

if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}

if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}
}
}

esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *str, uint8_t data_type, uint8_t *data, uint8_t data_len)
{
osi_mutex_t mutex_lock;
uint8_t *g_hci_log_buffer;

if (!p_hci_log_ctl->p_hci_log_buffer) {
return ESP_FAIL;
}

g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;

if (!g_hci_log_buffer) {
return ESP_FAIL;
}

mutex_lock = p_hci_log_ctl->mutex_lock;
osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT);

#if (1)
// Add hci data index
bt_hci_log_record_hex(p_hci_log_ctl, &p_hci_log_ctl->index, 1);
#endif

#if (BT_HCI_LOG_PRINT_TAG)
char *tag = NULL;
tag = bt_data_type_to_str(data_type);

if (tag) {
bt_hci_log_record_string(p_hci_log_ctl, tag);

g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ':';

if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}

if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}
}
#endif

if (str) {
bt_hci_log_record_string(p_hci_log_ctl, str);
}

bt_hci_log_record_hex(p_hci_log_ctl, data, data_len);

g_hci_log_buffer[p_hci_log_ctl->log_record_in] = '\n';

if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
}

if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
p_hci_log_ctl->overflow = true;
}

p_hci_log_ctl->index ++;

osi_mutex_unlock(&mutex_lock);

return ESP_OK;
}

void bt_hci_log_data_show(bt_hci_log_t *p_hci_log_ctl)
{
volatile uint64_t log_record_in,log_record_out;
uint8_t *g_hci_log_buffer;

if (!p_hci_log_ctl->p_hci_log_buffer) {
return;
}

osi_mutex_t mutex_lock = p_hci_log_ctl->mutex_lock;

osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT);

log_record_in = p_hci_log_ctl->log_record_in;
log_record_out = p_hci_log_ctl->log_record_out;

g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;

if (p_hci_log_ctl->overflow) {
log_record_out = log_record_in;
printf("%c",g_hci_log_buffer[log_record_out]);

if (++log_record_out >= p_hci_log_ctl->buf_size) {
log_record_out = 0;
}
}

while (log_record_in != log_record_out)
{
printf("%c",g_hci_log_buffer[log_record_out]);

if (++log_record_out >= p_hci_log_ctl->buf_size) {
log_record_out = 0;
}
}

p_hci_log_ctl->log_record_out = log_record_out;
p_hci_log_ctl->overflow = false;

osi_mutex_unlock(&mutex_lock);
}

esp_err_t IRAM_ATTR bt_hci_log_record_hci_data(uint8_t data_type, uint8_t *data, uint8_t data_len)
{
return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, NULL, data_type, data, data_len);
}

esp_err_t IRAM_ATTR bt_hci_log_record_custom_data(char *string, uint8_t *data, uint8_t data_len)
{
return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, string, HCI_LOG_DATA_TYPE_SELF_DEFINE, data, data_len);
}

esp_err_t IRAM_ATTR bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len)
{
return bt_hci_log_record_data(&g_bt_hci_log_adv_ctl, NULL, data_type, data, data_len);
}

void bt_hci_log_hci_data_show(void)
{
bt_hci_log_data_show(&g_bt_hci_log_data_ctl);
}

void bt_hci_log_hci_adv_show(void)
{
bt_hci_log_data_show(&g_bt_hci_log_adv_ctl);
}

#endif // (BT_HCI_LOG_INCLUDED == TRUE)
Loading

0 comments on commit 40d3981

Please sign in to comment.