From 2aae53c42a88c89d2ff278ed37bec2bd82800631 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:09:13 +0000 Subject: [PATCH 1/2] [Bugfix] Arduino 3.3.11 build/crash with esp32 c5/c6 vairants. --- .github/workflows/build.yml | 1 + .../esp_port/esp-hci/src/na_hci_transport.c | 2 +- src/nimble/esp_port/esp_ipc/src/hci_esp_ipc.c | 3 +-- .../porting/nimble/include/os/os_mempool.h | 16 +++++++++++++++- src/nimble/porting/nimble/src/nimble_port.c | 5 ++--- .../porting/npl/freertos/src/npl_os_freertos.c | 3 --- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c1e5c1f7..dcf5f580a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -185,6 +185,7 @@ jobs: - "examples/NimBLE_Server" variant: - esp32 + - esp32c5 - esp32c3 - esp32s3 - esp32c6 diff --git a/src/nimble/esp_port/esp-hci/src/na_hci_transport.c b/src/nimble/esp_port/esp-hci/src/na_hci_transport.c index 2307c9753..4ac05ca46 100644 --- a/src/nimble/esp_port/esp-hci/src/na_hci_transport.c +++ b/src/nimble/esp_port/esp-hci/src/na_hci_transport.c @@ -6,7 +6,7 @@ #ifdef ESP_PLATFORM #include "syscfg/syscfg.h" -#if CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT && CONFIG_BT_BLUEDROID_ENABLED +#if CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT #include #include diff --git a/src/nimble/esp_port/esp_ipc/src/hci_esp_ipc.c b/src/nimble/esp_port/esp_ipc/src/hci_esp_ipc.c index e80f3018e..b8931cf27 100644 --- a/src/nimble/esp_port/esp_ipc/src/hci_esp_ipc.c +++ b/src/nimble/esp_port/esp_ipc/src/hci_esp_ipc.c @@ -6,8 +6,7 @@ #include #ifdef ESP_PLATFORM -# if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && \ - !defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_BT_BLUEDROID_ENABLED +# if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) #include #include diff --git a/src/nimble/porting/nimble/include/os/os_mempool.h b/src/nimble/porting/nimble/include/os/os_mempool.h index d1ed87265..f9bdca515 100644 --- a/src/nimble/porting/nimble/include/os/os_mempool.h +++ b/src/nimble/porting/nimble/include/os/os_mempool.h @@ -32,6 +32,17 @@ #include "nimble/porting/nimble/include/os/os.h" #include "nimble/porting/nimble/include/os/queue.h" +#if defined(ARDUINO_ARCH_ESP32) && __has_include("esp_arduino_version.h") +#include "esp_arduino_version.h" +#endif + +#if defined(ESP_ARDUINO_VERSION) +/* Arduino ESP32 core 3.3.11+ dropped the legacy r_ prefix for these mempool symbols. */ +#define NIMBLE_OS_MEMPOOL_USE_ROM_R_PREFIX (ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 3, 11)) +#else +#define NIMBLE_OS_MEMPOOL_USE_ROM_R_PREFIX 1 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -170,7 +181,7 @@ typedef __uint128_t os_membuf_t; #define OS_MEMPOOL_BYTES(n,blksize) \ (sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize))) -#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED && NIMBLE_OS_MEMPOOL_USE_ROM_R_PREFIX /** * Initialize a memory pool. * @@ -405,6 +416,9 @@ os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr); } #endif +/* Keep this version gate local to this header. */ +#undef NIMBLE_OS_MEMPOOL_USE_ROM_R_PREFIX + #endif /* _OS_MEMPOOL_H_ */ diff --git a/src/nimble/porting/nimble/src/nimble_port.c b/src/nimble/porting/nimble/src/nimble_port.c index b038d6db8..516ff0bda 100644 --- a/src/nimble/porting/nimble/src/nimble_port.c +++ b/src/nimble/porting/nimble/src/nimble_port.c @@ -95,7 +95,7 @@ esp_err_t esp_nimble_init(void) os_mempool_module_init(); os_msys_init(); -#elif CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT && CONFIG_BT_BLUEDROID_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT hci_transport_deinit(); na_hci_transport_init(HCI_TRANSPORT_VHCI); int na_npl_freertos_mempool_init(void); @@ -137,8 +137,7 @@ esp_err_t esp_nimble_deinit(void) ble_transport_ll_deinit(); -#if CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT && CONFIG_BT_BLUEDROID_ENABLED - na_hci_transport_deinit(); +#if CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT void na_npl_freertos_mempool_deinit(void); na_npl_freertos_mempool_deinit(); ble_npl_eventq_deinit(&g_eventq_dflt); diff --git a/src/nimble/porting/npl/freertos/src/npl_os_freertos.c b/src/nimble/porting/npl/freertos/src/npl_os_freertos.c index 57d6517dc..c3600b389 100644 --- a/src/nimble/porting/npl/freertos/src/npl_os_freertos.c +++ b/src/nimble/porting/npl/freertos/src/npl_os_freertos.c @@ -661,7 +661,6 @@ static os_membuf_t *ble_freertos_mutex_buf = NULL; static uint16_t ble_freertos_total_event_cnt = 0; -#if CONFIG_BT_BLUEDROID_ENABLED int na_npl_freertos_mempool_init(void) { int rc = -1; @@ -818,5 +817,3 @@ na_npl_freertos_eventq_init(struct ble_npl_eventq *evq) } } #endif /* CONFIG_BT_BLUEDROID_ENABLED */ - -#endif From 60e93df51ca89899fe53a29161c228b6cb7d5e49 Mon Sep 17 00:00:00 2001 From: h2zero Date: Wed, 29 Jul 2026 16:43:44 -0600 Subject: [PATCH 2/2] [Bugfix] scan response timer causing crash on reinit cycle. Fixes a crash when the stack is reinitialized without clearing all data on deinit then starting scanning. --- src/NimBLEDevice.cpp | 6 ++++++ src/NimBLEScan.cpp | 41 +++++++++++++++++++++++++++++++++++------ src/NimBLEScan.h | 2 ++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index e140d6205..d698d9cc8 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -1029,6 +1029,12 @@ bool NimBLEDevice::init(const std::string& deviceName) { bool NimBLEDevice::deinit(bool clearAll) { int rc = 0; if (m_initialized) { +# if MYNEWT_VAL(BLE_ROLE_OBSERVER) + if (NimBLEDevice::m_pScan != nullptr) { + NimBLEDevice::m_pScan->onHostDeinit(); + } +# endif + rc = nimble_port_stop(); if (rc == 0) { nimble_port_deinit(); diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index 81700d29d..0eac4b641 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -73,7 +73,6 @@ NimBLEScan::NimBLEScan() m_scanParams{0, 0, BLE_HCI_SCAN_FILT_NO_WL, 0, 1, 1}, m_pTaskData{nullptr}, m_maxResults{0xFF} { - ble_npl_callout_init(&m_srTimer, nimble_port_get_dflt_eventq(), NimBLEScan::srTimerCb, nullptr); ble_npl_time_ms_to_ticks(DEFAULT_SCAN_RESP_TIMEOUT_MS, &m_srTimeoutTicks); } // NimBLEScan::NimBLEScan @@ -81,7 +80,10 @@ NimBLEScan::NimBLEScan() * @brief Scan destructor, release any allocated resources. */ NimBLEScan::~NimBLEScan() { - ble_npl_callout_deinit(&m_srTimer); + if (m_srTimerInitialized) { + ble_npl_callout_deinit(&m_srTimer); + m_srTimerInitialized = false; + } for (const auto& dev : m_scanResults.m_deviceVec) { delete dev; @@ -167,7 +169,9 @@ void NimBLEScan::removeWaitingDevice(NimBLEAdvertisedDevice* pDev) { void NimBLEScan::clearWaitingList() { // Stop the timer and remove any pending timeout events since we're clearing // the list and won't be processing any more timeouts for these devices - ble_npl_callout_stop(&m_srTimer); + if (m_srTimerInitialized) { + ble_npl_callout_stop(&m_srTimer); + } ble_npl_hw_enter_critical(); NimBLEAdvertisedDevice* current = m_pWaitingListHead; while (current != nullptr) { @@ -185,10 +189,19 @@ void NimBLEScan::clearWaitingList() { */ void NimBLEScan::resetWaitingTimer() { if (m_srTimeoutTicks == 0 || m_pWaitingListHead == nullptr) { - ble_npl_callout_stop(&m_srTimer); + if (m_srTimerInitialized) { + ble_npl_callout_stop(&m_srTimer); + } return; } + if (!m_srTimerInitialized) { + m_srTimerInitialized = ble_npl_callout_init(&m_srTimer, nimble_port_get_dflt_eventq(), NimBLEScan::srTimerCb, nullptr) == 0; + if (!m_srTimerInitialized) { + return; + } + } + ble_npl_time_t now = ble_npl_time_get(); ble_npl_time_t elapsed = now - m_pWaitingListHead->m_time; ble_npl_time_t nextTime = elapsed >= m_srTimeoutTicks ? 1 : m_srTimeoutTicks - elapsed; @@ -335,7 +348,9 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { } case BLE_GAP_EVENT_DISC_COMPLETE: { - ble_npl_callout_stop(&pScan->m_srTimer); + if (pScan->m_srTimerInitialized) { + ble_npl_callout_stop(&pScan->m_srTimer); + } // If we have any scannable devices that haven't received a scan response, // we should trigger the callback with whatever data we have since the scan is complete @@ -381,7 +396,9 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { */ void NimBLEScan::setScanResponseTimeout(uint32_t timeoutMs) { if (timeoutMs == 0) { - ble_npl_callout_stop(&m_srTimer); + if (m_srTimerInitialized) { + ble_npl_callout_stop(&m_srTimer); + } m_srTimeoutTicks = 0; return; } @@ -662,6 +679,18 @@ void NimBLEScan::onHostSync() { m_pScanCallbacks->onScanEnd(m_scanResults, BLE_HS_ENOTSYNCED); } +/** + * @brief Called before host deinit so callouts don't outlive the default event queue. + */ +void NimBLEScan::onHostDeinit() { + clearWaitingList(); + + if (m_srTimerInitialized) { + ble_npl_callout_deinit(&m_srTimer); + m_srTimerInitialized = false; + } +} + /** * @brief Start scanning and block until scanning has been completed. * @param [in] duration The duration in milliseconds for which to scan. diff --git a/src/NimBLEScan.h b/src/NimBLEScan.h index 0c612851d..89c858c8d 100644 --- a/src/NimBLEScan.h +++ b/src/NimBLEScan.h @@ -181,6 +181,7 @@ class NimBLEScan { ~NimBLEScan(); static int handleGapEvent(ble_gap_event* event, void* arg); void onHostSync(); + void onHostDeinit(); static void srTimerCb(ble_npl_event* event); // Linked list helpers for devices awaiting scan responses @@ -194,6 +195,7 @@ class NimBLEScan { NimBLEScanResults m_scanResults; NimBLEUtils::TaskData* m_pTaskData; ble_npl_callout m_srTimer{}; + bool m_srTimerInitialized{false}; ble_npl_time_t m_srTimeoutTicks{}; uint8_t m_maxResults; NimBLEAdvertisedDevice* m_pWaitingListHead{}; // head of linked list for devices awaiting scan responses