Merge branch 'bugfix/queue_att_cmd' into 'master'

feat(nimble): Defer all ATT commands until connection event is sent to GAP layer

See merge request espressif/esp-idf!47838
This commit is contained in:
Rahul Tank
2026-07-03 16:01:07 +05:30
4 changed files with 79 additions and 32 deletions

View File

@@ -349,6 +349,16 @@ menu "GAP"
Enable this option to send number-of-completed-packets event to
controller after disconnection
config BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT
bool "Defer connection GAP/ATT events until CONNECT callback"
depends on BT_NIMBLE_ENABLED
default y
help
Queue connection-related GAP callbacks and ATT server requests until
BLE_GAP_EVENT_CONNECT event is delivered for that connection handle.
Required when the host delays CONNECT so applications never receive other
events before CONNECT event.
endmenu #GAP
menu "GATT / ATT"

View File

@@ -2390,4 +2390,13 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_DEFER_CONN_EVENTS
#ifdef CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT
#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT
#else
#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS (0)
#endif
#endif
#endif

View File

@@ -26,6 +26,7 @@
portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t npl_eventq_sync;
static uint8_t hw_critical_state_status[portNUM_PROCESSORS];
#if BLE_NPL_USE_ESP_TIMER
static const char *TAG = "Timer";
@@ -203,25 +204,35 @@ static void
npl_eventq_sync_init(void)
{
if (npl_eventq_sync == NULL) {
npl_eventq_sync = xSemaphoreCreateMutex();
npl_eventq_sync = xSemaphoreCreateRecursiveMutex();
BLE_LL_ASSERT(npl_eventq_sync);
}
}
static void
static bool
npl_eventq_lock(void)
{
if (!in_isr()) {
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTake(npl_eventq_sync, portMAX_DELAY);
BaseType_t core;
if (in_isr()) {
return false;
}
core = xPortGetCoreID();
if (core >= portNUM_PROCESSORS || hw_critical_state_status[core] != 0) {
return false;
}
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTakeRecursive(npl_eventq_sync, portMAX_DELAY);
return true;
}
static void
npl_eventq_unlock(void)
npl_eventq_unlock(bool locked)
{
if (!in_isr()) {
xSemaphoreGive(npl_eventq_sync);
if (locked) {
xSemaphoreGiveRecursive(npl_eventq_sync);
}
}
@@ -331,7 +342,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo
}
}
} else if (tmo == 0) {
npl_eventq_lock();
bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
@@ -341,7 +353,7 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo
}
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
npl_eventq_unlock(locked);
} else {
TickType_t deadline = 0;
TickType_t remaining;
@@ -364,7 +376,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo
return NULL;
}
npl_eventq_lock();
bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
@@ -372,12 +385,13 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo
if (event) {
event->queued = false;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
break;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
if (ret == pdPASS && ev != NULL) {
npl_eventq_unlock(locked);
break;
}
npl_eventq_unlock(locked);
}
}
@@ -407,10 +421,10 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve
}
return;
} else {
npl_eventq_lock();
bool locked = npl_eventq_lock();
if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock();
npl_eventq_unlock(locked);
return;
}
@@ -419,7 +433,7 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve
ESP_LOGW("NimBLE", "eventq put: queue full, event dropped");
npl_eventq_queued_set_task(event, false);
}
npl_eventq_unlock();
npl_eventq_unlock(locked);
}
}
@@ -446,10 +460,10 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl
}
return;
} else {
npl_eventq_lock();
bool locked = npl_eventq_lock();
if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock();
npl_eventq_unlock(locked);
return;
}
@@ -458,7 +472,7 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl
ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped");
npl_eventq_queued_set_task(event, false);
}
npl_eventq_unlock();
npl_eventq_unlock(locked);
}
}
@@ -522,9 +536,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
} else {
removed = false;
npl_eventq_lock();
bool locked = npl_eventq_lock();
if (!npl_eventq_queued_get_task(event)) {
npl_eventq_unlock();
npl_eventq_unlock(locked);
return;
}
@@ -548,11 +563,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
}
}
if (removed) {
event->queued = 0;
event->queued = false;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
npl_eventq_unlock(locked);
}
}
@@ -1231,26 +1245,40 @@ IRAM_ATTR npl_freertos_time_delay(ble_npl_time_t ticks)
}
uint8_t hw_critical_state_status = 0;
uint32_t
IRAM_ATTR npl_freertos_hw_enter_critical(void)
{
++hw_critical_state_status;
BaseType_t core;
portENTER_CRITICAL(&ble_port_mutex);
core = xPortGetCoreID();
if (core < portNUM_PROCESSORS) {
++hw_critical_state_status[core];
}
return 0;
}
uint8_t
IRAM_ATTR npl_freertos_hw_is_in_critical(void)
{
return hw_critical_state_status;
BaseType_t core;
core = xPortGetCoreID();
if (core >= portNUM_PROCESSORS) {
return 0;
}
return hw_critical_state_status[core];
}
void
IRAM_ATTR npl_freertos_hw_exit_critical(uint32_t ctx)
{
--hw_critical_state_status;
BaseType_t core;
core = xPortGetCoreID();
if (core < portNUM_PROCESSORS && hw_critical_state_status[core] > 0) {
--hw_critical_state_status[core];
}
portEXIT_CRITICAL(&ble_port_mutex);
}