mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(nimble): Memory optimization + dynamic memory support
This commit is contained in:
@@ -29,3 +29,82 @@ void bt_osi_mem_count_limit_set(uint16_t count_limit);
|
||||
size_t bt_osi_mem_internal_used_size_get(void);
|
||||
size_t bt_osi_mem_used_size_get(void);
|
||||
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
|
||||
#if CONFIG_BT_NIMBLE_MEM_DEBUG
|
||||
/**
|
||||
* @brief Initialize NimBLE memory debug module
|
||||
*/
|
||||
void nimble_mem_dbg_init(void);
|
||||
|
||||
/**
|
||||
* @brief Record memory allocation information
|
||||
*
|
||||
* @param p Pointer to allocated memory
|
||||
* @param size Size of allocation
|
||||
* @param func Function name where allocation occurred
|
||||
* @param line Line number where allocation occurred
|
||||
*/
|
||||
void nimble_mem_dbg_record(void *p, int size, const char *func, int line);
|
||||
|
||||
/**
|
||||
* @brief Clean up memory allocation record
|
||||
*
|
||||
* @param p Pointer to memory being freed
|
||||
* @param func Function name where free occurred
|
||||
* @param line Line number where free occurred
|
||||
*/
|
||||
void nimble_mem_dbg_clean(void *p, const char *func, int line);
|
||||
|
||||
/**
|
||||
* @brief Display all memory debug information
|
||||
*/
|
||||
void nimble_mem_dbg_show(void);
|
||||
|
||||
/**
|
||||
* @brief Get maximum memory size used
|
||||
*
|
||||
* @return Maximum memory size in bytes
|
||||
*/
|
||||
uint32_t nimble_mem_dbg_get_max_size(void);
|
||||
|
||||
/**
|
||||
* @brief Get current memory size in use
|
||||
*
|
||||
* @return Current memory size in bytes
|
||||
*/
|
||||
uint32_t nimble_mem_dbg_get_current_size(void);
|
||||
|
||||
/**
|
||||
* @brief Start tracking memory usage for a specific section
|
||||
*
|
||||
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
|
||||
*/
|
||||
void nimble_mem_dbg_set_section_start(uint8_t index);
|
||||
|
||||
/**
|
||||
* @brief Stop tracking memory usage for a specific section
|
||||
*
|
||||
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
|
||||
*/
|
||||
void nimble_mem_dbg_set_section_end(uint8_t index);
|
||||
|
||||
/**
|
||||
* @brief Get maximum memory size used in a specific section
|
||||
*
|
||||
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
|
||||
* @return Maximum memory size in bytes for this section
|
||||
*/
|
||||
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index);
|
||||
|
||||
/**
|
||||
* @brief Reallocate memory with debug tracking
|
||||
*
|
||||
* @param ptr Pointer to memory to reallocate
|
||||
* @param new_size New size of allocation
|
||||
* @param func Function name where realloc occurred
|
||||
* @param line Line number where realloc occurred
|
||||
* @return Pointer to reallocated memory
|
||||
*/
|
||||
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line);
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
|
||||
|
||||
@@ -19,7 +19,248 @@ static size_t host_mem_used_size = 0;
|
||||
static uint16_t mem_count_limit = 0;
|
||||
static uint16_t curr_mem_count;
|
||||
#endif // CONFIG_BT_LE_MEM_CHECK_ENABLED
|
||||
IRAM_ATTR void *bt_osi_mem_malloc(size_t size)
|
||||
|
||||
#if CONFIG_BT_NIMBLE_MEM_DEBUG
|
||||
|
||||
#define NIMBLE_MEM_DBG_INFO_MAX 1024*3
|
||||
typedef struct {
|
||||
void *p;
|
||||
int size;
|
||||
const char *func;
|
||||
int line;
|
||||
} nimble_mem_dbg_info_t;
|
||||
|
||||
static uint32_t nimble_mem_dbg_count = 0;
|
||||
static nimble_mem_dbg_info_t nimble_mem_dbg_info[NIMBLE_MEM_DBG_INFO_MAX];
|
||||
static uint32_t nimble_mem_dbg_current_size = 0;
|
||||
static uint32_t nimble_mem_dbg_max_size = 0;
|
||||
|
||||
#define NIMBLE_MEM_DBG_MAX_SECTION_NUM 5
|
||||
typedef struct {
|
||||
bool used;
|
||||
uint32_t max_size;
|
||||
} nimble_mem_dbg_max_size_section_t;
|
||||
static nimble_mem_dbg_max_size_section_t nimble_mem_dbg_max_size_section[NIMBLE_MEM_DBG_MAX_SECTION_NUM];
|
||||
|
||||
void nimble_mem_dbg_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
nimble_mem_dbg_info[i].p = NULL;
|
||||
nimble_mem_dbg_info[i].size = 0;
|
||||
nimble_mem_dbg_info[i].func = NULL;
|
||||
nimble_mem_dbg_info[i].line = 0;
|
||||
}
|
||||
nimble_mem_dbg_count = 0;
|
||||
nimble_mem_dbg_current_size = 0;
|
||||
nimble_mem_dbg_max_size = 0;
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
|
||||
nimble_mem_dbg_max_size_section[i].used = false;
|
||||
nimble_mem_dbg_max_size_section[i].max_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void nimble_mem_dbg_record(void *p, int size, const char *func, int line)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p || size == 0) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "%s invalid !!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
if (nimble_mem_dbg_info[i].p == NULL) {
|
||||
nimble_mem_dbg_info[i].p = p;
|
||||
nimble_mem_dbg_info[i].size = size;
|
||||
nimble_mem_dbg_info[i].func = func;
|
||||
nimble_mem_dbg_info[i].line = line;
|
||||
nimble_mem_dbg_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
|
||||
}
|
||||
|
||||
nimble_mem_dbg_current_size += size;
|
||||
if(nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
|
||||
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
|
||||
}
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
|
||||
if (nimble_mem_dbg_max_size_section[i].used) {
|
||||
if(nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
|
||||
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nimble_mem_dbg_clean(void *p, const char *func, int line)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "%s %d free->%p invalid\n", func, line, p);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
if (nimble_mem_dbg_info[i].p == p) {
|
||||
nimble_mem_dbg_current_size -= nimble_mem_dbg_info[i].size;
|
||||
nimble_mem_dbg_info[i].p = NULL;
|
||||
nimble_mem_dbg_info[i].size = 0;
|
||||
nimble_mem_dbg_info[i].func = NULL;
|
||||
nimble_mem_dbg_info[i].line = 0;
|
||||
nimble_mem_dbg_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
|
||||
}
|
||||
}
|
||||
|
||||
void nimble_mem_dbg_show(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
if (nimble_mem_dbg_info[i].p || nimble_mem_dbg_info[i].size != 0 ) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "--> p %p, s %d, f %s, l %d\n",
|
||||
nimble_mem_dbg_info[i].p, nimble_mem_dbg_info[i].size,
|
||||
nimble_mem_dbg_info[i].func, nimble_mem_dbg_info[i].line);
|
||||
}
|
||||
}
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "--> count %ld\n", nimble_mem_dbg_count);
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "--> size %ldB\n--> max size %ldB\n",
|
||||
nimble_mem_dbg_current_size, nimble_mem_dbg_max_size);
|
||||
}
|
||||
|
||||
uint32_t nimble_mem_dbg_get_max_size(void)
|
||||
{
|
||||
return nimble_mem_dbg_max_size;
|
||||
}
|
||||
|
||||
uint32_t nimble_mem_dbg_get_current_size(void)
|
||||
{
|
||||
return nimble_mem_dbg_current_size;
|
||||
}
|
||||
|
||||
void nimble_mem_dbg_set_section_start(uint8_t index)
|
||||
{
|
||||
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nimble_mem_dbg_max_size_section[index].used) {
|
||||
ESP_LOGW("BT_NIMBLE_MEM", "This index(%d) has been started, restart it.\n", index);
|
||||
}
|
||||
|
||||
nimble_mem_dbg_max_size_section[index].used = true;
|
||||
nimble_mem_dbg_max_size_section[index].max_size = nimble_mem_dbg_current_size;
|
||||
}
|
||||
|
||||
void nimble_mem_dbg_set_section_end(uint8_t index)
|
||||
{
|
||||
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nimble_mem_dbg_max_size_section[index].used) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "This index(%d) has not been started.\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
nimble_mem_dbg_max_size_section[index].used = false;
|
||||
}
|
||||
|
||||
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index)
|
||||
{
|
||||
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM){
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nimble_mem_dbg_max_size_section[index].max_size;
|
||||
}
|
||||
|
||||
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line)
|
||||
{
|
||||
size_t old_size = 0;
|
||||
int i;
|
||||
|
||||
void *new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr == NULL && new_size > 0) {
|
||||
// realloc failed, keep old ptr record
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find and clean old record if ptr is not NULL
|
||||
if (ptr != NULL) {
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
if (nimble_mem_dbg_info[i].p == ptr) {
|
||||
old_size = nimble_mem_dbg_info[i].size;
|
||||
nimble_mem_dbg_current_size -= old_size;
|
||||
|
||||
nimble_mem_dbg_info[i].p = NULL;
|
||||
nimble_mem_dbg_info[i].size = 0;
|
||||
nimble_mem_dbg_info[i].func = NULL;
|
||||
nimble_mem_dbg_info[i].line = 0;
|
||||
nimble_mem_dbg_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record the new allocation if new_size > 0
|
||||
if (new_ptr != NULL && new_size > 0) {
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
|
||||
if (nimble_mem_dbg_info[i].p == NULL) {
|
||||
nimble_mem_dbg_info[i].p = new_ptr;
|
||||
nimble_mem_dbg_info[i].size = new_size;
|
||||
nimble_mem_dbg_info[i].func = func;
|
||||
nimble_mem_dbg_info[i].line = line;
|
||||
nimble_mem_dbg_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
|
||||
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
|
||||
}
|
||||
|
||||
nimble_mem_dbg_current_size += new_size;
|
||||
if (nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
|
||||
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
|
||||
}
|
||||
|
||||
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++) {
|
||||
if (nimble_mem_dbg_max_size_section[i].used &&
|
||||
nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
|
||||
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
|
||||
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void *bt_osi_mem_malloc(size_t size)
|
||||
{
|
||||
void *mem = NULL;
|
||||
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
|
||||
@@ -47,7 +288,10 @@ IRAM_ATTR void *bt_osi_mem_malloc(size_t size)
|
||||
return mem;
|
||||
}
|
||||
|
||||
IRAM_ATTR void *bt_osi_mem_calloc(size_t n, size_t size)
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void *bt_osi_mem_calloc(size_t n, size_t size)
|
||||
{
|
||||
void *mem = NULL;
|
||||
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
|
||||
@@ -67,7 +311,10 @@ IRAM_ATTR void *bt_osi_mem_calloc(size_t n, size_t size)
|
||||
return mem;
|
||||
}
|
||||
|
||||
IRAM_ATTR void *bt_osi_mem_malloc_internal(size_t size)
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void *bt_osi_mem_malloc_internal(size_t size)
|
||||
{
|
||||
void *mem_ptr;
|
||||
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
|
||||
@@ -87,7 +334,10 @@ IRAM_ATTR void *bt_osi_mem_malloc_internal(size_t size)
|
||||
return mem_ptr;
|
||||
}
|
||||
|
||||
IRAM_ATTR void *bt_osi_mem_calloc_internal(size_t n, size_t size)
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void *bt_osi_mem_calloc_internal(size_t n, size_t size)
|
||||
{
|
||||
void *mem_ptr;
|
||||
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
|
||||
@@ -107,7 +357,10 @@ IRAM_ATTR void *bt_osi_mem_calloc_internal(size_t n, size_t size)
|
||||
return mem_ptr;
|
||||
}
|
||||
|
||||
IRAM_ATTR void bt_osi_mem_free_internal(void *ptr)
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void bt_osi_mem_free_internal(void *ptr)
|
||||
{
|
||||
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
if (ptr) {
|
||||
@@ -116,10 +369,15 @@ IRAM_ATTR void bt_osi_mem_free_internal(void *ptr)
|
||||
controller_mem_used_size -= alloc_size;
|
||||
}
|
||||
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
heap_caps_free(ptr);
|
||||
if (ptr) {
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void bt_osi_mem_free(void *ptr)
|
||||
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
void bt_osi_mem_free(void *ptr)
|
||||
{
|
||||
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
if (ptr) {
|
||||
@@ -128,7 +386,9 @@ IRAM_ATTR void bt_osi_mem_free(void *ptr)
|
||||
host_mem_used_size -= alloc_size;
|
||||
}
|
||||
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
heap_caps_free(ptr);
|
||||
if (ptr) {
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mem_api.h"
|
||||
#include "bt_osi_mem.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_nimble_mem.h"
|
||||
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "syscfg/syscfg.h"
|
||||
@@ -168,17 +169,17 @@ int
|
||||
os_msys_buf_alloc(void)
|
||||
{
|
||||
#if OS_MSYS_1_BLOCK_COUNT > 0
|
||||
os_msys_init_1_data = (os_membuf_t *)bt_osi_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_1_MEMPOOL_SIZE));
|
||||
os_msys_init_1_data = (os_membuf_t *)nimble_platform_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_1_MEMPOOL_SIZE));
|
||||
if (!os_msys_init_1_data) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OS_MSYS_2_BLOCK_COUNT > 0
|
||||
os_msys_init_2_data = (os_membuf_t *)bt_osi_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_2_MEMPOOL_SIZE));
|
||||
os_msys_init_2_data = (os_membuf_t *)nimble_platform_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_2_MEMPOOL_SIZE));
|
||||
if (!os_msys_init_2_data) {
|
||||
#if OS_MSYS_1_BLOCK_COUNT > 0
|
||||
bt_osi_mem_free(os_msys_init_1_data);
|
||||
nimble_platform_mem_free(os_msys_init_1_data);
|
||||
os_msys_init_1_data = NULL;
|
||||
#endif
|
||||
return ESP_ERR_NO_MEM;
|
||||
@@ -192,12 +193,12 @@ void
|
||||
os_msys_buf_free(void)
|
||||
{
|
||||
#if OS_MSYS_1_BLOCK_COUNT > 0
|
||||
bt_osi_mem_free(os_msys_init_1_data);
|
||||
nimble_platform_mem_free(os_msys_init_1_data);
|
||||
os_msys_init_1_data = NULL;
|
||||
#endif
|
||||
|
||||
#if OS_MSYS_2_BLOCK_COUNT > 0
|
||||
bt_osi_mem_free(os_msys_init_2_data);
|
||||
nimble_platform_mem_free(os_msys_init_2_data);
|
||||
os_msys_init_2_data = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -165,6 +165,13 @@ npl_freertos_eventq_deinit(struct ble_npl_eventq *evq)
|
||||
{
|
||||
struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq;
|
||||
|
||||
#if CONFIG_BT_NIMBLE_STATIC_TO_DYNAMIC
|
||||
/* Deinit can be invoked twice without init . Handle this case */
|
||||
if (eventq == NULL) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
BLE_LL_ASSERT(eventq);
|
||||
vQueueDelete(eventq->q);
|
||||
#if OS_MEM_ALLOC
|
||||
|
||||
@@ -26,9 +26,11 @@ hci_transport_controller_packet_rx(hci_driver_data_type_t data_type, uint8_t *da
|
||||
r_ble_hci_trans_hs_cmd_tx(data);
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED || (CONFIG_BT_NIMBLE_ENABLED && (CONFIG_BT_NIMBLE_ROLE_CENTRAL || CONFIG_BT_NIMBLE_ROLE_PERIPHERAL))
|
||||
if (data_type == HCI_DRIVER_TYPE_ACL) {
|
||||
r_ble_hci_trans_hs_acl_tx((struct os_mbuf *) data);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user