diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 3bb4ce8179d..71bdb3cb83d 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -10,23 +10,18 @@ #include "mesh/PhoneAPI.h" #include "mesh/mesh-pb-constants.h" #include "sleep.h" -#include +#include +#include +#include +#include +#include #include #include -#ifdef NIMBLE_TWO -#include "NimBLEAdvertising.h" -#include "NimBLEExtAdvertising.h" #include "PowerStatus.h" -#endif -#if defined(CONFIG_NIMBLE_CPP_IDF) #include "host/ble_gap.h" -#else -#include "nimble/nimble/host/include/host/ble_gap.h" -#endif - -#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6) +#include "host/ble_store.h" namespace { @@ -34,7 +29,6 @@ constexpr uint16_t kPreferredBleMtu = 517; constexpr uint16_t kPreferredBleTxOctets = 251; constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8; } // namespace -#endif // Debugging options: careful, they slow things down quite a bit! // #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration @@ -44,10 +38,10 @@ constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8; #define NIMBLE_BLUETOOTH_TO_PHONE_QUEUE_SIZE 3 #define NIMBLE_BLUETOOTH_FROM_PHONE_QUEUE_SIZE 3 -NimBLECharacteristic *fromNumCharacteristic; -NimBLECharacteristic *BatteryCharacteristic; -NimBLECharacteristic *logRadioCharacteristic; -NimBLEServer *bleServer; +BLECharacteristic *fromNumCharacteristic; +BLECharacteristic *BatteryCharacteristic; +BLECharacteristic *logRadioCharacteristic; +BLEServer *bleServer; static bool passkeyShowing; static std::atomic nimbleBluetoothConnHandle{BLE_HS_CONN_HANDLE_NONE}; // BLE_HS_CONN_HANDLE_NONE means "no connection" @@ -118,7 +112,8 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread - Yes, we have to do some copy operations on pop because of this, but it's worth it to avoid cross-task memory management. NOTIFY IS BROKEN: - - Adding NIMBLE_PROPERTY::NOTIFY to FromRadioCharacteristic appears to break things. It is NOT backwards compatible. + - Adding BLECharacteristic::PROPERTY_NOTIFY to FromRadioCharacteristic appears to break things. It is NOT backwards + compatible. ZERO-SIZE READS: - Returning a zero-size read from onRead breaks some clients during the config phase. So we have to block onRead until we @@ -139,7 +134,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread std::mutex fromPhoneMutex; std::atomic fromPhoneQueueSize{0}; // We use array here (and pay the cost of memcpy) to avoid dynamic memory allocations and frees across FreeRTOS tasks. - std::array fromPhoneQueue{}; + std::array fromPhoneQueue{}; /* Packets to phone (BLE onRead callback) */ std::mutex toPhoneMutex; @@ -301,7 +296,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread LOG_DEBUG("NimbleBluetooth: handling ToRadio packet, fromPhoneQueueSize=%u", fromPhoneQueueSize.load()); // Pop the front of fromPhoneQueue, holding the mutex only briefly while we pop. - NimBLEAttValue val; + BLEValue val; { // scope for fromPhoneMutex mutex std::lock_guard guard(fromPhoneMutex); val = fromPhoneQueue[0]; @@ -316,7 +311,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread fromPhoneQueueSize--; } - handleToRadio(val.data(), val.length()); + handleToRadio(val.getData(), val.getLength()); } } @@ -328,9 +323,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread PhoneAPI::onNowHasData(fromRadioNum); #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); @@ -340,13 +333,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 @@ -409,14 +396,9 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI; // Last ToRadio value received from the phone static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE]; -class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks +class NimbleBluetoothToRadioCallback : public BLECharacteristicCallbacks { -#ifdef NIMBLE_TWO - virtual void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) -#else - virtual void onWrite(NimBLECharacteristic *pCharacteristic) - -#endif + void onWrite(BLECharacteristic *pCharacteristic) 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. @@ -428,15 +410,17 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks LOG_DEBUG("BLE onWrite(%d): start millis=%d", currentWriteCount, startMillis); #endif - auto val = pCharacteristic->getValue(); + // Create a BLEValue and populate it with the received data + BLEValue val; + val.setValue(pCharacteristic->getData(), pCharacteristic->getLength()); - if (memcmp(lastToRadio, val.data(), val.length()) != 0) { + if (memcmp(lastToRadio, val.getData(), val.getLength()) != 0) { if (bluetoothPhoneAPI->fromPhoneQueueSize < NIMBLE_BLUETOOTH_FROM_PHONE_QUEUE_SIZE) { // Note: the comparison above is safe without a mutex because we are the only method that *increases* // fromPhoneQueueSize. (It's okay if fromPhoneQueueSize *decreases* in the main task meanwhile.) - memcpy(lastToRadio, val.data(), val.length()); + memcpy(lastToRadio, val.getData(), val.getLength()); - { // scope for fromPhoneMutex mutex + { // scope for fromPhoneMutex mutexv, pCharacteristic->getLen // Append to fromPhoneQueue, protected by fromPhoneMutex. Hold the mutex as briefly as possible. std::lock_guard guard(bluetoothPhoneAPI->fromPhoneMutex); bluetoothPhoneAPI->fromPhoneQueue.at(bluetoothPhoneAPI->fromPhoneQueueSize) = val; @@ -450,24 +434,21 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks #ifdef DEBUG_NIMBLE_ON_WRITE_TIMING int finishMillis = millis(); LOG_DEBUG("BLE onWrite(%d): append to fromPhoneQueue took %u ms. numBytes=%d", currentWriteCount, - finishMillis - startMillis, val.length()); + finishMillis - startMillis, val.getLength()); #endif } else { - LOG_WARN("BLE onWrite(%d): Drop ToRadio packet, fromPhoneQueue full (%u bytes)", currentWriteCount, val.length()); + LOG_WARN("BLE onWrite(%d): Drop ToRadio packet, fromPhoneQueue full (%u bytes)", currentWriteCount, + val.getLength()); } } else { - LOG_DEBUG("BLE onWrite(%d): Drop duplicate ToRadio packet (%u bytes)", currentWriteCount, val.length()); + LOG_DEBUG("BLE onWrite(%d): Drop duplicate ToRadio packet (%u bytes)", currentWriteCount, val.getLength()); } } }; -class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks +class NimbleBluetoothFromRadioCallback : public BLECharacteristicCallbacks { -#ifdef NIMBLE_TWO - virtual void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) -#else - virtual void onRead(NimBLECharacteristic *pCharacteristic) -#endif + void onRead(BLECharacteristic *pCharacteristic) override { // CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce. @@ -573,34 +554,15 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks } }; -class NimbleBluetoothServerCallback : public NimBLEServerCallbacks +class NimbleBluetoothSecurityCallback : public BLESecurityCallbacks { -#ifdef NIMBLE_TWO - public: - NimbleBluetoothServerCallback(NimbleBluetooth *ble) { this->ble = ble; } - - private: - NimbleBluetooth *ble; - - virtual uint32_t onPassKeyDisplay() -#else - virtual uint32_t onPassKeyRequest() -#endif + void onPassKeyNotify(uint32_t passkey) 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"; @@ -630,15 +592,8 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks } #endif passkeyShowing = true; - - return passkey; } - -#ifdef NIMBLE_TWO - virtual void onAuthenticationComplete(NimBLEConnInfo &connInfo) -#else - virtual void onAuthenticationComplete(ble_gap_conn_desc *desc) -#endif + void onAuthenticationComplete(ble_gap_conn_desc *desc) override { LOG_INFO("BLE authentication complete"); @@ -646,58 +601,47 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks bluetoothStatus->updateStatus(&newStatus); clearPairingDisplay(); - // Store the connection handle for future use -#ifdef NIMBLE_TWO - nimbleBluetoothConnHandle = connInfo.getConnHandle(); -#else nimbleBluetoothConnHandle = desc->conn_handle; -#endif } +}; + +class NimbleBluetoothServerCallback : public BLEServerCallbacks +{ + public: + explicit NimbleBluetoothServerCallback(NimbleBluetooth *ble) : ble(ble) {} + + private: + NimbleBluetooth *ble; -#ifdef NIMBLE_TWO - virtual void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) + void onConnect(BLEServer *pServer, struct ble_gap_conn_desc *desc) { - LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str()); - - const uint16_t connHandle = connInfo.getConnHandle(); -#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6)) - int phyResult = - ble_gap_set_prefered_le_phy(connHandle, BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_CODED_ANY); - if (phyResult == 0) { - LOG_INFO("BLE conn %u requested 2M PHY", connHandle); - } else { - LOG_WARN("Failed to prefer 2M PHY for conn %u, rc=%d", connHandle, phyResult); - } -#endif + BLEAddress peer_addr(desc->peer_id_addr); + LOG_INFO("BLE incoming connection %s", peer_addr.toString().c_str()); + + const uint16_t connHandle = desc->conn_handle; + // With Google Pixel 8 Android devices, this causes ESP32 device crash + // when phone reconnects. Disable this to make progress on the + // Arduino v3 migration while we investigate the Android compatibility + // issue. +#if 0 int dataLenResult = ble_gap_set_data_len(connHandle, kPreferredBleTxOctets, kPreferredBleTxTimeUs); if (dataLenResult == 0) { LOG_INFO("BLE conn %u requested data length %u bytes", connHandle, kPreferredBleTxOctets); } else { LOG_WARN("Failed to raise data length for conn %u, rc=%d", connHandle, dataLenResult); } +#endif - LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu); + LOG_INFO("BLE conn %u peer MTU %u (target %u)", connHandle, pServer->getPeerMTU(connHandle), kPreferredBleMtu); pServer->updateConnParams(connHandle, 6, 12, 0, 200); } -#endif -#ifdef NIMBLE_TWO - virtual void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) - { - LOG_INFO("BLE disconnect reason: %d", reason); -#else - virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc) + void onDisconnect(BLEServer *pServer, struct ble_gap_conn_desc *desc) { - LOG_INFO("BLE disconnect"); -#endif -#ifdef NIMBLE_TWO + LOG_INFO("BLE disconnected"); if (ble->isDeInit) return; -#else - if (nimbleBluetooth && nimbleBluetooth->isDeInit) - return; -#endif meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED); bluetoothStatus->updateStatus(&newStatus); @@ -722,43 +666,51 @@ 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() +{ + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->stop(); + pAdvertising->reset(); + + pAdvertising->addServiceUUID(MESH_SERVICE_UUID); + // if (powerStatus->getHasBattery() == 1) { + // pAdvertising->addServiceUUID(BLEUUID((uint16_t)0x180f)); + // } + + BLEAdvertisementData scan = BLEAdvertisementData(); + scan.setName(getDeviceName()); + pAdvertising->setScanResponseData(scan); + pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue + pAdvertising->setMaxPreferred(0x12); + + if (!pAdvertising->start(0)) { + LOG_ERROR("BLE failed to start advertising"); + } else { + 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(); + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->reset(); pAdvertising->stop(); #endif } -// Proper shutdown for ESP32. Needs reboot to reverse. void NimbleBluetooth::deinit() { #ifdef ARCH_ESP32 @@ -768,21 +720,17 @@ void NimbleBluetooth::deinit() #ifdef BLE_LED digitalWrite(BLE_LED, LED_STATE_OFF); #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() @@ -795,9 +743,9 @@ int NimbleBluetooth::getRssi() uint16_t connHandle = nimbleBluetoothConnHandle.load(); if (connHandle == BLE_HS_CONN_HANDLE_NONE) { - const auto peers = bleServer->getPeerDevices(); + const auto peers = bleServer->getPeerDevices(true); if (!peers.empty()) { - connHandle = peers.front(); + connHandle = peers.begin()->first; nimbleBluetoothConnHandle = connHandle; } } @@ -825,74 +773,84 @@ void NimbleBluetooth::setup() LOG_INFO("Init the NimBLE bluetooth module"); - NimBLEDevice::init(getDeviceName()); - NimBLEDevice::setPower(ESP_PWR_LVL_P9); + BLEDevice::init(getDeviceName()); + BLEDevice::setPower(ESP_PWR_LVL_P9); -#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6)) - int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu); + int mtuResult = BLEDevice::setMTU(kPreferredBleMtu); if (mtuResult == 0) { LOG_INFO("BLE MTU request set to %u", kPreferredBleMtu); } else { LOG_WARN("Unable to request MTU %u, rc=%d", kPreferredBleMtu, mtuResult); } - int phyResult = ble_gap_set_prefered_default_le_phy(BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_2M_MASK); - if (phyResult == 0) { - LOG_INFO("BLE default PHY preference set to 2M"); + BLESecurity *pSecurity = new BLESecurity(); + pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); + pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); + if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { + // Set IO capability to DisplayOnly for MITM authentication + pSecurity->setCapability(ESP_IO_CAP_OUT); + // Set the passkey + if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) { + LOG_INFO("Use random passkey"); + pSecurity->setPassKey(false); // generate a random passkey + } else { + LOG_INFO("Use fixed passkey"); + pSecurity->setPassKey(true, config.bluetooth.fixed_pin); + } + // Enable authorization requirements: + // - bonding: true (for persistent storage of the keys) + // - MITM: true (enables Man-In-The-Middle protection for password prompts) + // - secure connection: true (enables secure connection for encryption) + pSecurity->setAuthenticationMode(true, true, true); } else { - LOG_WARN("Failed to prefer 2M PHY by default, rc=%d", phyResult); + // No IO capability for no PIN mode + pSecurity->setCapability(ESP_IO_CAP_NONE); + // No PIN mode: no MITM protection + pSecurity->setAuthenticationMode(true, false, false); } - - int dataLenResult = ble_gap_write_sugg_def_data_len(kPreferredBleTxOctets, kPreferredBleTxTimeUs); - if (dataLenResult == 0) { - LOG_INFO("BLE suggested data length set to %u bytes", kPreferredBleTxOctets); - } else { - LOG_WARN("Failed to raise suggested data length (%u/%u), rc=%d", kPreferredBleTxOctets, kPreferredBleTxTimeUs, - dataLenResult); + // Set the security callbacks + BLEDevice::setSecurityCallbacks(new NimbleBluetoothSecurityCallback()); + bleServer = BLEDevice::createServer(); + + // BLEDevice::createServer calls ble_svc_gap_init, which resets the device + // name to default, so set it again. + int nameRc = ble_svc_gap_device_name_set(BLEDevice::getDeviceName().c_str()); + if (nameRc != 0) { + LOG_ERROR("ble_svc_gap_device_name_set: rc=%d %s", nameRc, BLEUtils::returnCodeToString(nameRc)); } -#endif - if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { - NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM | BLE_SM_PAIR_AUTHREQ_SC); - NimBLEDevice::setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID); - NimBLEDevice::setSecurityRespKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID); - NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); - } - bleServer = NimBLEDevice::createServer(); -#ifdef NIMBLE_TWO - NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(this); -#else - NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(); -#endif - bleServer->setCallbacks(serverCallbacks, true); + bleServer->setCallbacks(new NimbleBluetoothServerCallback(this)); setupService(); startAdvertising(); } void NimbleBluetooth::setupService() { - NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID); - NimBLECharacteristic *ToRadioCharacteristic; - NimBLECharacteristic *FromRadioCharacteristic; + BLEService *bleService = bleServer->createService(MESH_SERVICE_UUID); + BLECharacteristic *ToRadioCharacteristic; + BLECharacteristic *FromRadioCharacteristic; // Define the characteristics that the app is looking for if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { - ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); + ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE); // Allow notifications so phones can stream FromRadio without polling. - FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); - fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); - logRadioCharacteristic = - bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U); - } else { - ToRadioCharacteristic = bleService->createCharacteristic( - TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); - FromRadioCharacteristic = bleService->createCharacteristic( - FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, BLECharacteristic::PROPERTY_READ); fromNumCharacteristic = - bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + bleService->createCharacteristic(FROMNUM_UUID, BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ); + logRadioCharacteristic = bleService->createCharacteristic(LOGRADIO_UUID, BLECharacteristic::PROPERTY_NOTIFY | + BLECharacteristic::PROPERTY_READ); + } else { + ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_WRITE_AUTHEN | + BLECharacteristic::PROPERTY_WRITE_ENC); + FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_READ_AUTHEN | + BLECharacteristic::PROPERTY_READ_ENC); + fromNumCharacteristic = bleService->createCharacteristic( + FROMNUM_UUID, BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_READ_AUTHEN | BLECharacteristic::PROPERTY_READ_ENC); logRadioCharacteristic = bleService->createCharacteristic( - LOGRADIO_UUID, - NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); + LOGRADIO_UUID, BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_READ_AUTHEN | BLECharacteristic::PROPERTY_READ_ENC); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -905,76 +863,31 @@ void NimbleBluetooth::setupService() bleService->start(); // Setup the battery service - 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); + BLEService *batteryService = bleServer->createService(BLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service + BLE2904 *batteryLevelDescriptor = new BLE2904(); + batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8); batteryLevelDescriptor->setNamespace(1); batteryLevelDescriptor->setUnit(0x27ad); - + BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic) + (uint16_t)0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); + BatteryCharacteristic->addDescriptor(batteryLevelDescriptor); 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 } } void NimbleBluetooth::clearBonds() { LOG_INFO("Clearing bluetooth bonds!"); - NimBLEDevice::deleteAllBonds(); + ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_SEC, nullptr); + ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, nullptr); } void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) @@ -982,16 +895,14 @@ 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 + logRadioCharacteristic->setValue(logMessage, length); + logRadioCharacteristic->notify(); } void clearNVS() { - NimBLEDevice::deleteAllBonds(); + ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_SEC, nullptr); + ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, nullptr); #ifdef ARCH_ESP32 ESP.restart(); #endif diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index 458fa4a674c..2956fe6d0b9 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-common.ini b/variants/esp32/esp32-common.ini index 52de2acd537..6bc3cff6b6b 100644 --- a/variants/esp32/esp32-common.ini +++ b/variants/esp32/esp32-common.ini @@ -38,7 +38,11 @@ build_flags = -Isrc/platform/esp32 -std=gnu++17 -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + # DO NOT INCREASE THIS TO DEBUG. It appears to trigger a bug in ESP-IDF + # Bluetooth stack with Pixel 8 Android devices: + # https://github.com/espressif/esp-idf/issues/18126#issuecomment-4286197744 + # Once the bug is resolved, we can remove this warning. + -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DAXP_DEBUG_PORT=Serial -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING @@ -70,9 +74,10 @@ lib_deps = lib_ignore = segger_rtt + NimBLE-Arduino ESP32 BLE Arduino ; Ignore builtin NimBLE libs - BLE + ; BLE BluetoothSerial SimpleBLE WiFiProv @@ -132,7 +137,8 @@ custom_component_remove = custom_sdkconfig = ; CONFIG_LOG_DEFAULT_LEVEL=4 ; CONFIG_LOG_MAXIMUM_LEVEL=4 - ; CONFIG_BT_NIMBLE_CPP_LOG_LEVEL=1 + '# CONFIG_BT_NIMBLE_LOG_LEVEL_INFO is not set' + CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR=y CONFIG_LOG_COLORS=y CONFIG_ARDUHAL_LOG_COLORS=y CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y @@ -270,6 +276,7 @@ custom_sdkconfig = CONFIG_BT_NIMBLE_ENABLE_PERIODIC_SYNC=n CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV=n CONFIG_BT_NIMBLE_EXT_SCAN=n + CONFIG_BT_NIMBLE_EXT_ADV=n CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER=n CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_2M_PHY=n CONFIG_BT_NIMBLE_BLUFI_ENABLE=n @@ -281,7 +288,7 @@ custom_sdkconfig = CONFIG_BT_NIMBLE_TPS_SERVICE=n CONFIG_BT_NIMBLE_IAS_SERVICE=n CONFIG_BT_NIMBLE_LLS_SERVICE=n - CONFIG_BT_NIMBLE_SPS_SERVICE=n + CONFIG_BT_NIMBLE_SPS_SERVICE=y CONFIG_BT_NIMBLE_HR_SERVICE=n CONFIG_BT_NIMBLE_HID_SERVICE=n CONFIG_BT_NIMBLE_BAS_SERVICE=n @@ -320,7 +327,7 @@ custom_sdkconfig = CONFIG_ARDUINO_SELECTIVE_WiFi=y CONFIG_ARDUINO_SELECTIVE_NetworkClientSecure=y CONFIG_ARDUINO_SELECTIVE_WiFiProv=n - CONFIG_ARDUINO_SELECTIVE_BLE=n + CONFIG_ARDUINO_SELECTIVE_BLE=y CONFIG_ARDUINO_SELECTIVE_BluetoothSerial=n CONFIG_ARDUINO_SELECTIVE_SimpleBLE=n CONFIG_ARDUINO_SELECTIVE_RainMaker=n diff --git a/variants/esp32/esp32.ini b/variants/esp32/esp32.ini index 590a189be30..8dbc25237bd 100644 --- a/variants/esp32/esp32.ini +++ b/variants/esp32/esp32.ini @@ -31,8 +31,6 @@ lib_deps = ${environmental_base.lib_deps} ${environmental_extra_no_bsec.lib_deps} ${radiolib_base.lib_deps} - # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino - h2zero/NimBLE-Arduino@1.4.3 # TODO renovate https://github.com/mverch67/libpax/archive/6f52ee989301cdabaeef00bcbf93bff55708ce2f.zip # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib diff --git a/variants/esp32c3/esp32c3.ini b/variants/esp32c3/esp32c3.ini index 53dde131177..02042047f01 100644 --- a/variants/esp32c3/esp32c3.ini +++ b/variants/esp32c3/esp32c3.ini @@ -14,9 +14,9 @@ custom_sdkconfig = ${esp32_common.custom_sdkconfig} ; ESP32c3 doesn't support SD_MMC CONFIG_ARDUINO_SELECTIVE_SD_MMC=n - CONFIG_BT_NIMBLE_EXT_ADV=y - CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 - CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 + ; CONFIG_BT_NIMBLE_EXT_ADV=y + ; CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 + ; CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 lib_deps = ${esp32_common.lib_deps} diff --git a/variants/esp32c6/esp32c6.ini b/variants/esp32c6/esp32c6.ini index df6aaf746ab..ae91e6e81fd 100644 --- a/variants/esp32c6/esp32c6.ini +++ b/variants/esp32c6/esp32c6.ini @@ -20,9 +20,9 @@ custom_sdkconfig = ${esp32_common.custom_sdkconfig} ; ESP32c6 doesn't support SD_MMC CONFIG_ARDUINO_SELECTIVE_SD_MMC=n - CONFIG_BT_NIMBLE_EXT_ADV=y - CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 - CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 + ; CONFIG_BT_NIMBLE_EXT_ADV=y + ; CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 + ; CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 lib_ignore = ${esp32_common.lib_ignore} diff --git a/variants/esp32s3/esp32s3.ini b/variants/esp32s3/esp32s3.ini index 9423f650d3a..17b451d4246 100644 --- a/variants/esp32s3/esp32s3.ini +++ b/variants/esp32s3/esp32s3.ini @@ -10,9 +10,9 @@ build_flags = custom_sdkconfig = ${esp32_common.custom_sdkconfig} - CONFIG_BT_NIMBLE_EXT_ADV=y - CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 - CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 + ; CONFIG_BT_NIMBLE_EXT_ADV=y + ; CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=257 + ; CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2 lib_deps = ${esp32_common.lib_deps}