fix(nimble): Defer Events / ATT related information from stack

Defer Events/ ATT related GAP events from stack until connection
 event is sent to GAP layer
This commit is contained in:
Rahul Tank
2026-07-03 11:13:09 +05:30
parent 6df37e9bec
commit 2453200f60
4 changed files with 79 additions and 32 deletions
+10
View File
@@ -349,6 +349,16 @@ menu "GAP"
Enable this option to send number-of-completed-packets event to Enable this option to send number-of-completed-packets event to
controller after disconnection 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 endmenu #GAP
menu "GATT / ATT" menu "GATT / ATT"
@@ -2390,4 +2390,13 @@
#endif #endif
#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 #endif
@@ -26,6 +26,7 @@
portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t npl_eventq_sync; static SemaphoreHandle_t npl_eventq_sync;
static uint8_t hw_critical_state_status[portNUM_PROCESSORS];
#if BLE_NPL_USE_ESP_TIMER #if BLE_NPL_USE_ESP_TIMER
static const char *TAG = "Timer"; static const char *TAG = "Timer";
@@ -203,25 +204,35 @@ static void
npl_eventq_sync_init(void) npl_eventq_sync_init(void)
{ {
if (npl_eventq_sync == NULL) { if (npl_eventq_sync == NULL) {
npl_eventq_sync = xSemaphoreCreateMutex(); npl_eventq_sync = xSemaphoreCreateRecursiveMutex();
BLE_LL_ASSERT(npl_eventq_sync); BLE_LL_ASSERT(npl_eventq_sync);
} }
} }
static void static bool
npl_eventq_lock(void) npl_eventq_lock(void)
{ {
if (!in_isr()) { BaseType_t core;
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTake(npl_eventq_sync, portMAX_DELAY); 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 static void
npl_eventq_unlock(void) npl_eventq_unlock(bool locked)
{ {
if (!in_isr()) { if (locked) {
xSemaphoreGive(npl_eventq_sync); 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) { } else if (tmo == 0) {
npl_eventq_lock(); bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex); portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0); ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) { 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); portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock(); npl_eventq_unlock(locked);
} else { } else {
TickType_t deadline = 0; TickType_t deadline = 0;
TickType_t remaining; 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; return NULL;
} }
npl_eventq_lock(); bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex); portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0); ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) { 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) { if (event) {
event->queued = false; event->queued = false;
} }
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
break;
} }
portEXIT_CRITICAL(&ble_port_mutex); 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; return;
} else { } else {
npl_eventq_lock(); bool locked = npl_eventq_lock();
if (npl_eventq_queued_claim(event)) { if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock(); npl_eventq_unlock(locked);
return; 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"); ESP_LOGW("NimBLE", "eventq put: queue full, event dropped");
npl_eventq_queued_set_task(event, false); 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; return;
} else { } else {
npl_eventq_lock(); bool locked = npl_eventq_lock();
if (npl_eventq_queued_claim(event)) { if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock(); npl_eventq_unlock(locked);
return; 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"); ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped");
npl_eventq_queued_set_task(event, false); 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 { } else {
removed = false; removed = false;
npl_eventq_lock(); bool locked = npl_eventq_lock();
if (!npl_eventq_queued_get_task(event)) { if (!npl_eventq_queued_get_task(event)) {
npl_eventq_unlock(); npl_eventq_unlock(locked);
return; return;
} }
@@ -548,11 +563,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
} }
} }
if (removed) { if (removed) {
event->queued = 0; event->queued = false;
} }
portEXIT_CRITICAL(&ble_port_mutex); portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock(locked);
npl_eventq_unlock();
} }
} }
@@ -1231,26 +1245,40 @@ IRAM_ATTR npl_freertos_time_delay(ble_npl_time_t ticks)
} }
uint8_t hw_critical_state_status = 0;
uint32_t uint32_t
IRAM_ATTR npl_freertos_hw_enter_critical(void) IRAM_ATTR npl_freertos_hw_enter_critical(void)
{ {
++hw_critical_state_status; BaseType_t core;
portENTER_CRITICAL(&ble_port_mutex); portENTER_CRITICAL(&ble_port_mutex);
core = xPortGetCoreID();
if (core < portNUM_PROCESSORS) {
++hw_critical_state_status[core];
}
return 0; return 0;
} }
uint8_t uint8_t
IRAM_ATTR npl_freertos_hw_is_in_critical(void) 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 void
IRAM_ATTR npl_freertos_hw_exit_critical(uint32_t ctx) 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); portEXIT_CRITICAL(&ble_port_mutex);
} }