Merge branch 'bugfix/nimble_issues_02062026_v6.0' into 'release/v6.0'

fix(nimble):  Fix few nimble issues 02062026 (v6.0)

See merge request espressif/esp-idf!49153
This commit is contained in:
Rahul Tank
2026-06-29 21:52:48 +05:30
90 changed files with 2367 additions and 321 deletions
+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 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
menuconfig BLE_MESH
+1 -1
View File
@@ -94,7 +94,7 @@ list(APPEND bt_common_srcs
"${CMAKE_CURRENT_LIST_DIR}/api/esp_blufi_api.c"
"${CMAKE_CURRENT_LIST_DIR}/hci_log/bt_hci_log.c"
"${CMAKE_CURRENT_LIST_DIR}/btc/core/btc_manage.c"
# "${CMAKE_CURRENT_LIST_DIR}/hci_log/bt_hci_log_insights.c"
"${CMAKE_CURRENT_LIST_DIR}/hci_log/bt_hci_log_insights.c"
"${CMAKE_CURRENT_LIST_DIR}/btc/core/btc_task.c"
"${CMAKE_CURRENT_LIST_DIR}/btc/profile/esp/blufi/blufi_prf.c"
"${CMAKE_CURRENT_LIST_DIR}/btc/profile/esp/blufi/blufi_protocol.c"
+15
View File
@@ -6,6 +6,21 @@ config BT_ALARM_MAX_NUM
This option decides the maximum number of alarms which
could be used by Bluetooth host.
config BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT
bool "Allow BLE connection interval below Bluetooth Core Spec minimum (disable host check)"
depends on BT_BLE_ENABLED || BT_NIMBLE_ENABLED
default n
help
When enabled, BLE host-side validation accepts connection interval
values below the Bluetooth Core Specification minimum of 0x0006
(7.5 ms), down to non-zero values. The BLE controller still enforces
what is actually supported in hardware and firmware.
End users should NOT set this option directly. In typical IDF builds it
follows the active Controller integration when that Controller supports
this mode; use the Controller's own configuration instead of toggling
this host symbol manually.
choice BT_SMP_CRYPTO_STACK
prompt "SMP cryptographic stack"
depends on (BT_BLE_SMP_ENABLE || BT_SMP_ENABLE || BT_NIMBLE_SECURITY_ENABLE || BT_LE_SECURITY_ENABLE)
+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_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)
{
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
*/
@@ -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);
/**
*
* @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
}
#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
*/
@@ -100,6 +100,13 @@
#define BT_HCI_LOG_INCLUDED FALSE
#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
#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
@@ -117,10 +124,10 @@
#if UC_BT_HCI_LOG_DATA_BUFFER_SIZE
#define HCI_LOG_DATA_BUFFER_SIZE UC_BT_HCI_LOG_DATA_BUFFER_SIZE
#else
#define HCI_BUFFER_SIZE (5)
#define HCI_LOG_DATA_BUFFER_SIZE (5)
#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
#else
#define HCI_LOG_ADV_BUFFER_SIZE (5)
@@ -277,4 +284,8 @@ typedef struct {
#define BD_ADDR_LEN 6 /* Device address length */
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_ */
@@ -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
*/
@@ -176,4 +176,12 @@
#define UC_BT_HCI_LOG_ADV_BUFFER_SIZE (5)
#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__ */
+4 -7
View File
@@ -575,7 +575,7 @@ config BT_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS
config BT_CTRL_BLE_MIN_CONN_INTERVAL_ENABLE
bool "Allow BLE connection interval below the spec minimum"
default y
select BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT if BT_BLUEDROID_ENABLED
select BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT if BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED
help
Enabling this option allows the BLE controller to use a connection interval
smaller than the Bluetooth Core specification minimum of 7.5 ms. On
@@ -590,12 +590,9 @@ config BT_CTRL_BLE_MIN_CONN_INTERVAL_ENABLE
This option is enabled by default. Disable it to stay compliant with the BLE
specification (minimum connection interval 7.5 ms).
Host stack: When Bluedroid is the BLE host, enabling this option also selects
BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT so the host accepts connection
intervals below the spec minimum. NimBLE host does not provide equivalent
support yet; it is planned for a future release. Until then, use Bluedroid
if you need coordinated host and controller behavior for sub-minimum
intervals.
Host stack: Enabling this option also selects
BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT so the active BLE host accepts
connection intervals below the spec minimum.
menu "Controller debug log Options (Experimental)"
config BT_CTRL_LE_LOG_EN
-17
View File
@@ -1388,23 +1388,6 @@ config BT_BLE_RPA_TIMEOUT
This set RPA timeout of Controller and Host.
Default is 900 s (15 minutes). Range is 1 s to 1 hour (3600 s).
config BT_BLE_HOST_ALLOW_SUB_SPEC_MIN_CONN_INT
bool "Allow BLE connection interval below Bluetooth Core Spec minimum (disable host check)"
depends on BT_BLE_ENABLED
default n
help
When enabled, the Bluedroid host skips the minimum BLE connection
interval validation (Bluetooth Core Spec minimum is 0x0006 / 7.5 ms)
and accepts any non-zero interval value from the application. The
BLE controller then enforces what is actually allowed; how small the
connection interval may be depends on controller capability and its
own configuration, not on this host option text.
End users should NOT set this option directly. In typical IDF builds it
follows the active Controller integration when that Controller supports
this mode; use the Controller's own configuration (menu entries and symbol
names differ by chip) instead of toggling this host symbol manually.
menuconfig BT_BLE_50_FEATURES_SUPPORTED
bool "Enable BLE 5.0 and above features(please disable BLE 4.2 if enable BLE 5.0)"
depends on (BT_BLE_ENABLED && ((BT_CONTROLLER_ENABLED && SOC_BLE_50_SUPPORTED) || BT_CONTROLLER_DISABLED))
@@ -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
*/
@@ -8,6 +8,7 @@
#include "esp_log.h"
#include "esp_bluedroid_hci.h"
#include "common/bt_target.h"
#include "bt_common.h"
#include "hci/hci_trans_int.h"
#if (BT_CONTROLLER_INCLUDED == TRUE)
#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 (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
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
@@ -34,6 +34,7 @@
#include "esp_bt.h"
#endif
#include "esp_bluedroid_hci.h"
#include "bt_common.h"
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
#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)
)) {
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 {
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;
} 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);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(data_type, &data[1], len - 1);
#endif
}
#endif // (BT_HCI_LOG_INCLUDED == TRUE)
}
+8
View File
@@ -917,6 +917,14 @@ menu "Services"
help
Defines maximum number of report characteristics per service instance
config BT_NIMBLE_RAS_SERVICE
depends on BT_NIMBLE_CHANNEL_SOUNDING
bool "RAS service"
default y
help
Enable RAS Service
menuconfig BT_NIMBLE_BAS_SERVICE
bool "Battery service"
default y
@@ -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)
{
#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
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len);
@@ -178,7 +182,6 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
{
struct os_mbuf *m = NULL;
int rc;
int sr;
int retry_count = 1;
@@ -212,9 +215,7 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
os_mbuf_free_chain(m);
return;
}
OS_ENTER_CRITICAL(sr);
ble_transport_to_hs_acl(m);
OS_EXIT_CRITICAL(sr);
}
#endif
@@ -237,18 +238,24 @@ static void dummy_controller_rcv_pkt_ready(void)
void bt_record_hci_data(uint8_t *data, uint16_t len)
{
#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))) {
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 {
uint8_t data_type;
if (data[0] == HCI_LOG_DATA_TYPE_ISO_DATA) {
data_type = HCI_LOG_DATA_TYPE_ISO_DATA;
} 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 : 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 // (BT_HCI_LOG_INCLUDED == TRUE)
}
@@ -2382,4 +2382,12 @@
#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
@@ -25,6 +25,8 @@
portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t npl_eventq_sync;
#if BLE_NPL_USE_ESP_TIMER
static const char *TAG = "Timer";
#endif
@@ -197,6 +199,115 @@ IRAM_ATTR in_isr(void)
return xPortInIsrContext() != 0;
}
static void
npl_eventq_sync_init(void)
{
if (npl_eventq_sync == NULL) {
npl_eventq_sync = xSemaphoreCreateMutex();
BLE_LL_ASSERT(npl_eventq_sync);
}
}
static void
npl_eventq_lock(void)
{
if (!in_isr()) {
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTake(npl_eventq_sync, portMAX_DELAY);
}
}
static void
npl_eventq_unlock(void)
{
if (!in_isr()) {
xSemaphoreGive(npl_eventq_sync);
}
}
static bool IRAM_ATTR
npl_eventq_queued_get_isr(struct ble_npl_event_freertos *event)
{
bool queued;
portENTER_CRITICAL_ISR(&ble_port_mutex);
queued = event->queued;
portEXIT_CRITICAL_ISR(&ble_port_mutex);
return queued;
}
static void IRAM_ATTR
npl_eventq_queued_set_isr(struct ble_npl_event_freertos *event, bool queued)
{
portENTER_CRITICAL_ISR(&ble_port_mutex);
event->queued = queued;
portEXIT_CRITICAL_ISR(&ble_port_mutex);
}
static bool IRAM_ATTR
npl_eventq_queued_claim_isr(struct ble_npl_event_freertos *event)
{
bool already;
portENTER_CRITICAL_ISR(&ble_port_mutex);
already = event->queued;
if (!already) {
event->queued = true;
}
portEXIT_CRITICAL_ISR(&ble_port_mutex);
return already;
}
static void IRAM_ATTR
npl_eventq_queued_set_task(struct ble_npl_event_freertos *event, bool queued)
{
portENTER_CRITICAL(&ble_port_mutex);
event->queued = queued;
portEXIT_CRITICAL(&ble_port_mutex);
}
static bool IRAM_ATTR
npl_eventq_queued_get_task(struct ble_npl_event_freertos *event)
{
bool queued;
portENTER_CRITICAL(&ble_port_mutex);
queued = event->queued;
portEXIT_CRITICAL(&ble_port_mutex);
return queued;
}
static bool IRAM_ATTR
npl_eventq_queued_claim(struct ble_npl_event_freertos *event)
{
bool already;
portENTER_CRITICAL(&ble_port_mutex);
already = event->queued;
if (!already) {
event->queued = true;
}
portEXIT_CRITICAL(&ble_port_mutex);
return already;
}
static void IRAM_ATTR
npl_eventq_lost_event_clear(struct ble_npl_event *ev)
{
struct ble_npl_event_freertos *lost;
if (ev == NULL) {
return;
}
lost = (struct ble_npl_event_freertos *)ev->event;
if (lost == NULL) {
return;
}
lost->queued = false;
}
struct ble_npl_event *
IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
{
@@ -211,16 +322,63 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo
if( woken == pdTRUE ) {
portYIELD_FROM_ISR();
}
} else {
ret = xQueueReceive(eventq->q, &ev, tmo);
}
BLE_LL_ASSERT(ret == pdPASS || ret == errQUEUE_EMPTY);
BLE_LL_ASSERT(ret == pdPASS || ret == errQUEUE_EMPTY);
if (ev) {
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event) {
event->queued = false;
}
if (ev) {
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event) {
npl_eventq_queued_set_isr(event, false);
}
}
} else if (tmo == 0) {
npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event) {
event->queued = false;
}
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
} else {
TickType_t deadline = 0;
TickType_t remaining;
if (tmo != portMAX_DELAY) {
deadline = xTaskGetTickCount() + tmo;
}
for (;;) {
if (tmo == portMAX_DELAY) {
ret = xQueuePeek(eventq->q, &ev, portMAX_DELAY);
} else {
remaining = deadline - xTaskGetTickCount();
if (remaining > tmo) {
return NULL;
}
ret = xQueuePeek(eventq->q, &ev, remaining);
}
if (ret != pdPASS) {
return NULL;
}
npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event) {
event->queued = false;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
break;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
}
}
return ev;
@@ -234,22 +392,35 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve
struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq;
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event->queued) {
return;
}
event->queued = true;
if (in_isr()) {
if (npl_eventq_queued_claim_isr(event)) {
return;
}
ret = xQueueSendToBackFromISR(eventq->q, &ev, &woken);
if (ret != pdPASS) {
npl_eventq_queued_set_isr(event, false);
return;
}
if( woken == pdTRUE ) {
portYIELD_FROM_ISR();
}
return;
} else {
ret = xQueueSendToBack(eventq->q, &ev, portMAX_DELAY);
}
npl_eventq_lock();
BLE_LL_ASSERT(ret == pdPASS);
if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock();
return;
}
ret = xQueueSendToBack(eventq->q, &ev, 0);
if (ret != pdPASS) {
ESP_LOGW("NimBLE", "eventq put: queue full, event dropped");
npl_eventq_queued_set_task(event, false);
}
npl_eventq_unlock();
}
}
void
@@ -260,22 +431,35 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl
struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq;
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (event->queued) {
return;
}
event->queued = true;
if (in_isr()) {
if (npl_eventq_queued_claim_isr(event)) {
return;
}
ret = xQueueSendToFrontFromISR(eventq->q, &ev, &woken);
if (ret != pdPASS) {
npl_eventq_queued_set_isr(event, false);
return;
}
if( woken == pdTRUE ) {
portYIELD_FROM_ISR();
}
return;
} else {
ret = xQueueSendToFront(eventq->q, &ev, portMAX_DELAY);
}
npl_eventq_lock();
BLE_LL_ASSERT(ret == pdPASS);
if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock();
return;
}
ret = xQueueSendToFront(eventq->q, &ev, 0);
if (ret != pdPASS) {
ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped");
npl_eventq_queued_set_task(event, false);
}
npl_eventq_unlock();
}
}
void
@@ -286,14 +470,11 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
BaseType_t ret;
int i;
int count;
bool removed;
BaseType_t woken, woken2;
struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq;
struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event;
if (!event->queued) {
return;
}
/*
* XXX We cannot extract element from inside FreeRTOS queue so as a quick
* workaround we'll just remove all elements and add them back except the
@@ -302,46 +483,77 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
*/
if (in_isr()) {
if (!npl_eventq_queued_get_isr(event)) {
return;
}
removed = false;
woken = pdFALSE;
portENTER_CRITICAL_ISR(&ble_port_mutex);
count = uxQueueMessagesWaitingFromISR(eventq->q);
for (i = 0; i < count; i++) {
ret = xQueueReceiveFromISR(eventq->q, &tmp_ev, &woken2);
BLE_LL_ASSERT(ret == pdPASS);
if (ret != pdPASS) {
break;
}
woken |= woken2;
if (tmp_ev == ev) {
removed = true;
continue;
}
ret = xQueueSendToBackFromISR(eventq->q, &tmp_ev, &woken2);
BLE_LL_ASSERT(ret == pdPASS);
if (ret != pdPASS) {
npl_eventq_lost_event_clear(tmp_ev);
break;
}
woken |= woken2;
}
if (removed) {
event->queued = false;
}
portEXIT_CRITICAL_ISR(&ble_port_mutex);
if( woken == pdTRUE ) {
portYIELD_FROM_ISR();
}
} else {
portENTER_CRITICAL(&ble_port_mutex);
removed = false;
npl_eventq_lock();
if (!npl_eventq_queued_get_task(event)) {
npl_eventq_unlock();
return;
}
portENTER_CRITICAL(&ble_port_mutex);
count = uxQueueMessagesWaiting(eventq->q);
for (i = 0; i < count; i++) {
ret = xQueueReceive(eventq->q, &tmp_ev, 0);
BLE_LL_ASSERT(ret == pdPASS);
if (ret != pdPASS) {
break;
}
if (tmp_ev == ev) {
removed = true;
continue;
}
ret = xQueueSendToBack(eventq->q, &tmp_ev, 0);
BLE_LL_ASSERT(ret == pdPASS);
if (ret != pdPASS) {
npl_eventq_lost_event_clear(tmp_ev);
break;
}
}
if (removed) {
event->queued = 0;
}
portEXIT_CRITICAL(&ble_port_mutex);
}
event->queued = 0;
npl_eventq_unlock();
}
}
ble_npl_error_t
@@ -1116,6 +1328,9 @@ int npl_freertos_set_controller_npl_info(ble_npl_count_info_t *ctrl_npl_info)
int npl_freertos_mempool_init(void)
{
int rc = -1;
npl_eventq_sync_init();
uint16_t ble_total_evt_count = 0;
uint16_t ble_total_co_count = 0;
uint16_t ble_total_evtq_count = 0;
@@ -1205,6 +1420,11 @@ int npl_freertos_mempool_init(void)
return 0;
_error:
if (npl_eventq_sync) {
vSemaphoreDelete(npl_eventq_sync);
npl_eventq_sync = NULL;
}
if (ble_freertos_ev_buf) {
bt_osi_mem_free_internal(ble_freertos_ev_buf);
ble_freertos_ev_buf = NULL;
@@ -1234,6 +1454,11 @@ _error:
void npl_freertos_mempool_deinit(void)
{
if (npl_eventq_sync) {
vSemaphoreDelete(npl_eventq_sync);
npl_eventq_sync = NULL;
}
if (ble_freertos_ev_buf) {
bt_osi_mem_free_internal(ble_freertos_ev_buf);
ble_freertos_ev_buf = NULL;
+16 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -302,6 +302,21 @@ static void attach_report_listeners(esp_gatt_if_t gattc_if, esp_hidh_dev_t *dev)
//subscribe to battery notifications
if (dev->ble.battery_handle) {
uint8_t *rdata = NULL;
uint16_t rlen = 0;
if (event_loop_handle &&
read_char(gattc_if, dev->ble.conn_id, dev->ble.battery_handle,
ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK &&
rlen >= 1 && rdata != NULL) {
esp_hidh_event_data_t p = {0};
p.battery.dev = dev;
p.battery.level = rdata[0];
esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_BATTERY_EVENT,
&p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
}
free(rdata);
register_for_notify(gattc_if, dev->addr.bda, dev->ble.battery_handle);
if (dev->ble.battery_ccc_handle) {
//Write CCC descr to enable notifications
+132
View File
@@ -43,6 +43,9 @@ static void (*s_prev_sync_cb)(void) = NULL;
static struct ble_gap_event_listener nimble_gap_event_listener;
static void nimble_host_synced(void);
void nimble_host_reset(int reason);
static void nimble_report_write_cb(uint16_t attr_handle, uint8_t report_type, uint8_t report_id,
const uint8_t *data, uint16_t len);
static void nimble_char_write_cb(uint16_t attr_handle, uint16_t char_uuid16, uint8_t value);
static inline void lock_hidd(void)
{
@@ -349,6 +352,8 @@ static int nimble_hidd_dev_deinit(void *devp)
ble_hs_cfg.sync_cb = s_prev_sync_cb;
}
ble_hs_cfg.gatts_register_cb = NULL;
ble_svc_hid_register_report_write_cb(NULL);
ble_svc_hid_register_char_write_cb(NULL);
unlock_hidd();
/* Known timing issue: STOP_EVENT is posted here but ble_hid_free_config (called
@@ -425,6 +430,129 @@ static hidd_le_report_item_t* find_report_by_usage_and_type(uint8_t dev_index, u
return NULL;
}
static void nimble_report_write_cb(uint16_t attr_handle, uint8_t report_type, uint8_t report_id,
const uint8_t *data, uint16_t len)
{
lock_hidd();
if (s_dev == NULL || s_dev->event_loop_handle == NULL || data == NULL) {
unlock_hidd();
return;
}
hidd_le_report_item_t *match = NULL;
uint8_t map_index = 0;
for (uint8_t d = 0; d < s_dev->devices_len && match == NULL; d++) {
for (uint8_t r = 0; r < s_dev->devices[d].reports_len; r++) {
hidd_le_report_item_t *item = &s_dev->devices[d].reports[r];
if (item->handle == attr_handle) {
match = item;
map_index = d;
break;
}
}
}
if (match == NULL) {
unlock_hidd();
return;
}
if (report_type != ESP_HID_REPORT_TYPE_OUTPUT &&
report_type != ESP_HID_REPORT_TYPE_FEATURE) {
ESP_LOGD(TAG, "Ignoring host write for unsupported report type=%u, id=%u, handle=%u",
report_type, report_id, attr_handle);
unlock_hidd();
return;
}
size_t event_data_size = sizeof(esp_hidd_event_data_t);
if (len > 0) {
event_data_size += len;
}
esp_hidd_event_data_t *p_cb_param = (esp_hidd_event_data_t *)calloc(1, event_data_size);
if (p_cb_param == NULL) {
ESP_LOGE(TAG, "%s malloc event data failed!", __func__);
unlock_hidd();
return;
}
if (len > 0) {
memcpy(((uint8_t *)p_cb_param) + sizeof(esp_hidd_event_data_t), data, len);
}
if (report_type == ESP_HID_REPORT_TYPE_OUTPUT) {
p_cb_param->output.dev = s_dev->dev;
p_cb_param->output.usage = match->usage;
p_cb_param->output.report_id = report_id;
p_cb_param->output.length = len;
p_cb_param->output.data = (len > 0) ? (uint8_t *)data : NULL; /* fixed by esp_hidd_process_event_data_handler */
p_cb_param->output.map_index = map_index;
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_OUTPUT_EVENT,
p_cb_param, event_data_size, portMAX_DELAY);
} else if (report_type == ESP_HID_REPORT_TYPE_FEATURE) {
p_cb_param->feature.dev = s_dev->dev;
p_cb_param->feature.usage = match->usage;
p_cb_param->feature.report_id = report_id;
p_cb_param->feature.length = len;
p_cb_param->feature.data = (len > 0) ? (uint8_t *)data : NULL; /* fixed by esp_hidd_process_event_data_handler */
p_cb_param->feature.map_index = map_index;
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_FEATURE_EVENT,
p_cb_param, event_data_size, portMAX_DELAY);
}
free(p_cb_param);
unlock_hidd();
}
static void nimble_char_write_cb(uint16_t attr_handle, uint16_t char_uuid16, uint8_t value)
{
lock_hidd();
if (s_dev == NULL || s_dev->event_loop_handle == NULL) {
unlock_hidd();
return;
}
uint8_t map_index = 0;
bool found = false;
for (uint8_t d = 0; d < s_dev->devices_len; d++) {
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE &&
s_dev->devices[d].hid_protocol_handle == attr_handle) {
found = true;
map_index = d;
break;
}
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT &&
s_dev->devices[d].hid_control_handle == attr_handle) {
found = true;
map_index = d;
break;
}
}
if (!found) {
unlock_hidd();
return;
}
esp_hidd_event_data_t cb_param = {0};
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE) {
s_dev->protocol = value;
cb_param.protocol_mode.dev = s_dev->dev;
cb_param.protocol_mode.protocol_mode = value;
cb_param.protocol_mode.map_index = map_index;
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_PROTOCOL_MODE_EVENT,
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
} else if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT) {
s_dev->control = value;
cb_param.control.dev = s_dev->dev;
cb_param.control.control = value;
cb_param.control.map_index = map_index;
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONTROL_EVENT,
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
}
unlock_hidd();
}
static int nimble_hidd_dev_input_set(void *devp, size_t index, size_t id, uint8_t *data, size_t length)
{
hidd_le_report_item_t *p_rpt;
@@ -843,6 +971,8 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
ble_hs_cfg.reset_cb = nimble_host_reset;
ble_hs_cfg.sync_cb = nimble_host_synced;
ble_hs_cfg.gatts_register_cb = nimble_gatt_svr_register_cb;
ble_svc_hid_register_report_write_cb(nimble_report_write_cb);
ble_svc_hid_register_char_write_cb(nimble_char_write_cb);
rc = nimble_hid_start_gatts();
if (rc != ESP_OK) {
if (ble_hs_cfg.reset_cb == nimble_host_reset) {
@@ -852,6 +982,8 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
ble_hs_cfg.sync_cb = s_prev_sync_cb;
}
ble_hs_cfg.gatts_register_cb = NULL;
ble_svc_hid_register_report_write_cb(NULL);
ble_svc_hid_register_char_write_cb(NULL);
ble_hidd_dev_free();
return rc;
}
+17 -3
View File
@@ -70,14 +70,14 @@ static inline void SEND_CB(void)
static inline void LOCK_OPS(void)
{
if (s_ble_hidh_op_mutex) {
xSemaphoreTake(s_ble_hidh_op_mutex, portMAX_DELAY);
xSemaphoreTakeRecursive(s_ble_hidh_op_mutex, portMAX_DELAY);
}
}
static inline void UNLOCK_OPS(void)
{
if (s_ble_hidh_op_mutex) {
xSemaphoreGive(s_ble_hidh_op_mutex);
xSemaphoreGiveRecursive(s_ble_hidh_op_mutex);
}
}
@@ -789,6 +789,20 @@ static void attach_report_listeners(esp_hidh_dev_t *dev)
report = dev->reports;
if (dev->ble.battery_handle) {
uint8_t *rdata = NULL;
uint16_t rlen = 0;
if (event_loop_handle &&
read_char(dev->ble.conn_id, dev->ble.battery_handle, &rdata, &rlen) == 0 &&
rlen >= 1 && rdata != NULL) {
esp_hidh_event_data_t p = {0};
p.battery.dev = dev;
p.battery.level = rdata[0];
esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_BATTERY_EVENT,
&p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
}
free(rdata);
register_for_notify(dev->ble.conn_id, dev->ble.battery_handle);
if (dev->ble.battery_ccc_handle && dev->ble.conn_id >= 0 && dev->connected) {
write_char_descr(dev, dev->ble.battery_ccc_handle, 2, (uint8_t *)&ccc_data);
@@ -1174,7 +1188,7 @@ esp_err_t esp_ble_hidh_init(const esp_hidh_config_t *config)
s_ble_hidh_cb_semaphore = xSemaphoreCreateBinary();
ESP_RETURN_ON_FALSE(s_ble_hidh_cb_semaphore,
ESP_ERR_NO_MEM, TAG, "Allocation failed");
s_ble_hidh_op_mutex = xSemaphoreCreateMutex();
s_ble_hidh_op_mutex = xSemaphoreCreateRecursiveMutex();
if (s_ble_hidh_op_mutex == NULL) {
vSemaphoreDelete(s_ble_hidh_cb_semaphore);
s_ble_hidh_cb_semaphore = NULL;