From f3785e4cebfeea7745a9caab0f33a7377c99428a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 17 Dec 2025 08:04:22 -0600 Subject: [PATCH] Upgrade all esp32 targets to NimBLE 2.X --- src/nimble/NimbleBluetooth.cpp | 206 ++++++------------ src/nimble/NimbleBluetooth.h | 5 - variants/esp32/esp32.ini | 3 +- variants/esp32c3/esp32c3.ini | 5 + .../esp32c6/m5stack_unitc6l/platformio.ini | 3 +- variants/esp32s3/esp32s3.ini | 5 + 6 files changed, 83 insertions(+), 144 deletions(-) diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 3b98eca3d..637641ff9 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -14,11 +14,11 @@ #include #include -#ifdef NIMBLE_TWO #include "NimBLEAdvertising.h" +#ifdef CONFIG_BT_NIMBLE_EXT_ADV #include "NimBLEExtAdvertising.h" -#include "PowerStatus.h" #endif +#include "PowerStatus.h" #if defined(CONFIG_NIMBLE_CPP_IDF) #include "host/ble_gap.h" @@ -313,11 +313,9 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread { PhoneAPI::onNowHasData(fromRadioNum); - int currentNotifyCount = notifyCount.fetch_add(1); - - uint8_t cc = bleServer->getConnectedCount(); - #ifdef DEBUG_NIMBLE_NOTIFY + int currentNotifyCount = notifyCount.fetch_add(1); + uint8_t cc = bleServer->getConnectedCount(); // This logging slows things down when there are lots of packets going to the phone, like initial connection: LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc); #endif @@ -326,13 +324,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread put_le32(val, fromRadioNum); fromNumCharacteristic->setValue(val, sizeof(val)); -#ifdef NIMBLE_TWO - // NOTE: I don't have any NIMBLE_TWO devices, but this line makes me suspicious, and I suspect it needs to just be - // notify(). fromNumCharacteristic->notify(val, sizeof(val), BLE_HS_CONN_HANDLE_NONE); -#else - fromNumCharacteristic->notify(); -#endif } /// Check the current underlying physical link to see if the client is currently connected @@ -397,12 +389,7 @@ static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE]; class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks { -#ifdef NIMBLE_TWO - virtual void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) -#else - virtual void onWrite(NimBLECharacteristic *pCharacteristic) - -#endif + void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override { // CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce. // Assumption: onWrite is serialized by NimBLE, so we don't need to lock here against multiple concurrent onWrite calls. @@ -449,11 +436,7 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { -#ifdef NIMBLE_TWO - virtual void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) -#else - virtual void onRead(NimBLECharacteristic *pCharacteristic) -#endif + void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override { // CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce. @@ -561,32 +544,27 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks class NimbleBluetoothServerCallback : public NimBLEServerCallbacks { -#ifdef NIMBLE_TWO public: - NimbleBluetoothServerCallback(NimbleBluetooth *ble) { this->ble = ble; } + explicit NimbleBluetoothServerCallback(NimbleBluetooth *ble) : ble(ble) {} private: NimbleBluetooth *ble; - virtual uint32_t onPassKeyDisplay() -#else - virtual uint32_t onPassKeyRequest() -#endif + uint32_t onPassKeyDisplay() override { uint32_t passkey = config.bluetooth.fixed_pin; if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) { LOG_INFO("Use random passkey"); - // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits passkey = random(100000, 999999); } - LOG_INFO("*** Enter passkey %d on the peer side ***", passkey); + LOG_INFO("*** Enter passkey %06u on the peer side ***", passkey); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); meshtastic::BluetoothStatus newStatus(std::to_string(passkey)); bluetoothStatus->updateStatus(&newStatus); -#if HAS_SCREEN // Todo: migrate this display code back into Screen class, and observe bluetoothStatus +#if HAS_SCREEN if (screen) { screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { char btPIN[16] = "888888"; @@ -615,39 +593,29 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks }); } #endif - passkeyShowing = true; + passkeyShowing = true; return passkey; } -#ifdef NIMBLE_TWO - virtual void onAuthenticationComplete(NimBLEConnInfo &connInfo) -#else - virtual void onAuthenticationComplete(ble_gap_conn_desc *desc) -#endif + void onAuthenticationComplete(NimBLEConnInfo &connInfo) override { LOG_INFO("BLE authentication complete"); meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED); bluetoothStatus->updateStatus(&newStatus); - // Todo: migrate this display code back into Screen class, and observe bluetoothStatus if (passkeyShowing) { passkeyShowing = false; - if (screen) + if (screen) { screen->endAlert(); + } } - // Store the connection handle for future use -#ifdef NIMBLE_TWO nimbleBluetoothConnHandle = connInfo.getConnHandle(); -#else - nimbleBluetoothConnHandle = desc->conn_handle; -#endif } -#ifdef NIMBLE_TWO - virtual void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) + void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) override { LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str()); @@ -672,21 +640,12 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu); pServer->updateConnParams(connHandle, 6, 12, 0, 200); } -#endif -#ifdef NIMBLE_TWO - virtual void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) + void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) override { LOG_INFO("BLE disconnect reason: %d", reason); -#else - virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc) - { - LOG_INFO("BLE disconnect"); -#endif -#ifdef NIMBLE_TWO if (ble->isDeInit) return; -#endif meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED); bluetoothStatus->updateStatus(&newStatus); @@ -710,35 +669,69 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks bluetoothPhoneAPI->writeCount = 0; } - // Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection memset(lastToRadio, 0, sizeof(lastToRadio)); - nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE; // BLE_HS_CONN_HANDLE_NONE means "no connection" + nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE; -#ifdef NIMBLE_TWO - // Restart Advertising ble->startAdvertising(); -#else - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - if (!pAdvertising->start(0)) { - if (pAdvertising->isAdvertising()) { - LOG_DEBUG("BLE advertising already running"); - } else { - LOG_ERROR("BLE failed to restart advertising"); - } - } -#endif } }; static NimbleBluetoothToRadioCallback *toRadioCallbacks; static NimbleBluetoothFromRadioCallback *fromRadioCallbacks; +void NimbleBluetooth::startAdvertising() +{ +#if defined(CONFIG_BT_NIMBLE_EXT_ADV) + NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); + NimBLEExtAdvertisement legacyAdvertising; + + legacyAdvertising.setLegacyAdvertising(true); + legacyAdvertising.setScannable(true); + legacyAdvertising.setConnectable(true); + legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN); + if (powerStatus->getHasBattery() == 1) { + legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f)); + } + legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID)); + legacyAdvertising.setMinInterval(500); + legacyAdvertising.setMaxInterval(1000); + + NimBLEExtAdvertisement legacyScanResponse; + legacyScanResponse.setLegacyAdvertising(true); + legacyScanResponse.setConnectable(true); + legacyScanResponse.setName(getDeviceName()); + + if (!pAdvertising->setInstanceData(0, legacyAdvertising)) { + LOG_ERROR("BLE failed to set legacyAdvertising"); + } else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) { + LOG_ERROR("BLE failed to set legacyScanResponse"); + } else if (!pAdvertising->start(0, 0, 0)) { + LOG_ERROR("BLE failed to start legacyAdvertising"); + } +#else + NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); + pAdvertising->reset(); + pAdvertising->addServiceUUID(MESH_SERVICE_UUID); + if (powerStatus->getHasBattery() == 1) { + pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f)); + } + + NimBLEAdvertisementData scan; + scan.setName(getDeviceName()); + pAdvertising->setScanResponseData(scan); + pAdvertising->enableScanResponse(true); + + if (!pAdvertising->start(0)) { + LOG_ERROR("BLE failed to start advertising"); + } +#endif + LOG_DEBUG("BLE Advertising started"); +} + void NimbleBluetooth::shutdown() { - // No measurable power saving for ESP32 during light-sleep(?) #ifndef ARCH_ESP32 - // Shutdown bluetooth for minimum power draw LOG_INFO("Disable bluetooth"); NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); pAdvertising->reset(); @@ -746,7 +739,6 @@ void NimbleBluetooth::shutdown() #endif } -// Proper shutdown for ESP32. Needs reboot to reverse. void NimbleBluetooth::deinit() { #ifdef ARCH_ESP32 @@ -760,21 +752,17 @@ void NimbleBluetooth::deinit() digitalWrite(BLE_LED, LOW); #endif #endif -#ifndef NIMBLE_TWO - NimBLEDevice::deinit(); -#endif #endif } -// Has initial setup been completed bool NimbleBluetooth::isActive() { - return bleServer; + return bleServer != nullptr; } bool NimbleBluetooth::isConnected() { - return bleServer->getConnectedCount() > 0; + return bleServer && bleServer->getConnectedCount() > 0; } int NimbleBluetooth::getRssi() @@ -818,7 +806,7 @@ void NimbleBluetooth::setup() LOG_INFO("Init the NimBLE bluetooth module"); NimBLEDevice::init(getDeviceName()); - NimBLEDevice::setPower(ESP_PWR_LVL_P9); + NimBLEDevice::setPower(9); #if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6)) int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu); @@ -851,11 +839,7 @@ void NimbleBluetooth::setup() NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); } bleServer = NimBLEDevice::createServer(); -#ifdef NIMBLE_TWO - NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(this); -#else - NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(); -#endif + auto *serverCallbacks = new NimbleBluetoothServerCallback(this); bleServer->setCallbacks(serverCallbacks, true); setupService(); startAdvertising(); @@ -900,11 +884,7 @@ void NimbleBluetooth::setupService() NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic) (uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1); -#ifdef NIMBLE_TWO NimBLE2904 *batteryLevelDescriptor = BatteryCharacteristic->create2904(); -#else - NimBLE2904 *batteryLevelDescriptor = (NimBLE2904 *)BatteryCharacteristic->createDescriptor((uint16_t)0x2904); -#endif batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8); batteryLevelDescriptor->setNamespace(1); batteryLevelDescriptor->setUnit(0x27ad); @@ -912,54 +892,12 @@ void NimbleBluetooth::setupService() batteryService->start(); } -void NimbleBluetooth::startAdvertising() -{ -#ifdef NIMBLE_TWO - NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - NimBLEExtAdvertisement legacyAdvertising; - - legacyAdvertising.setLegacyAdvertising(true); - legacyAdvertising.setScannable(true); - legacyAdvertising.setConnectable(true); - legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN); - if (powerStatus->getHasBattery() == 1) { - legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f)); - } - legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID)); - legacyAdvertising.setMinInterval(500); - legacyAdvertising.setMaxInterval(1000); - - NimBLEExtAdvertisement legacyScanResponse; - legacyScanResponse.setLegacyAdvertising(true); - legacyScanResponse.setConnectable(true); - legacyScanResponse.setName(getDeviceName()); - - if (!pAdvertising->setInstanceData(0, legacyAdvertising)) { - LOG_ERROR("BLE failed to set legacyAdvertising"); - } else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) { - LOG_ERROR("BLE failed to set legacyScanResponse"); - } else if (!pAdvertising->start(0, 0, 0)) { - LOG_ERROR("BLE failed to start legacyAdvertising"); - } -#else - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - pAdvertising->reset(); - pAdvertising->addServiceUUID(MESH_SERVICE_UUID); - pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service - pAdvertising->start(0); -#endif -} - /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level) { if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) { BatteryCharacteristic->setValue(&level, 1); -#ifdef NIMBLE_TWO BatteryCharacteristic->notify(&level, 1, BLE_HS_CONN_HANDLE_NONE); -#else - BatteryCharacteristic->notify(); -#endif } } @@ -974,11 +912,7 @@ void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) if (!bleServer || !isConnected() || length > 512) { return; } -#ifdef NIMBLE_TWO logRadioCharacteristic->notify(logMessage, length, BLE_HS_CONN_HANDLE_NONE); -#else - logRadioCharacteristic->notify(logMessage, length, true); -#endif } void clearNVS() diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index 458fa4a67..2956fe6d0 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -12,16 +12,11 @@ class NimbleBluetooth : BluetoothApi bool isConnected(); int getRssi(); void sendLog(const uint8_t *logMessage, size_t length); -#if defined(NIMBLE_TWO) void startAdvertising(); -#endif bool isDeInit = false; private: void setupService(); -#if !defined(NIMBLE_TWO) - void startAdvertising(); -#endif }; void setBluetoothEnable(bool enable); diff --git a/variants/esp32/esp32.ini b/variants/esp32/esp32.ini index 4bc48cebb..85a85165e 100644 --- a/variants/esp32/esp32.ini +++ b/variants/esp32/esp32.ini @@ -38,6 +38,7 @@ build_flags = -DAXP_DEBUG_PORT=Serial -DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3 + -DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192 @@ -59,7 +60,7 @@ lib_deps = # renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino - h2zero/NimBLE-Arduino@^1.4.3 + h2zero/NimBLE-Arduino@^2.3.7 # renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip # renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib diff --git a/variants/esp32c3/esp32c3.ini b/variants/esp32c3/esp32c3.ini index 2ba3036d0..07f8bcdd1 100644 --- a/variants/esp32c3/esp32c3.ini +++ b/variants/esp32c3/esp32c3.ini @@ -4,3 +4,8 @@ custom_esp32_kind = esp32c3 monitor_speed = 115200 monitor_filters = esp32_c3_exception_decoder + +build_flags = + ${esp32_base.build_flags} + -DCONFIG_BT_NIMBLE_EXT_ADV=1 + -DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 diff --git a/variants/esp32c6/m5stack_unitc6l/platformio.ini b/variants/esp32c6/m5stack_unitc6l/platformio.ini index 9992ab2bf..ac6b90336 100644 --- a/variants/esp32c6/m5stack_unitc6l/platformio.ini +++ b/variants/esp32c6/m5stack_unitc6l/platformio.ini @@ -13,7 +13,7 @@ build_unflags = lib_deps = ${esp32c6_base.lib_deps} adafruit/Adafruit NeoPixel@^1.12.3 - h2zero/NimBLE-Arduino@^2.3.6 + h2zero/NimBLE-Arduino@^2.3.7 build_flags = ${esp32c6_base.build_flags} -D M5STACK_UNITC6L @@ -24,7 +24,6 @@ build_flags = -D HAS_BLUETOOTH=1 -DCONFIG_BT_NIMBLE_EXT_ADV=1 -DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 - -D NIMBLE_TWO monitor_speed=115200 lib_ignore = NonBlockingRTTTL diff --git a/variants/esp32s3/esp32s3.ini b/variants/esp32s3/esp32s3.ini index 8d8b6899e..3230323ec 100644 --- a/variants/esp32s3/esp32s3.ini +++ b/variants/esp32s3/esp32s3.ini @@ -3,3 +3,8 @@ extends = esp32_base custom_esp32_kind = esp32s3 monitor_speed = 115200 + +build_flags = + ${esp32_base.build_flags} + -DCONFIG_BT_NIMBLE_EXT_ADV=1 + -DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2