Skip to content

Commit

Permalink
automatically delete bonds when changing NimBLE version from 1.4.x to…
Browse files Browse the repository at this point in the history
… 2.0.x or vice versa
  • Loading branch information
KlausMu committed Dec 12, 2024
1 parent 77a4c86 commit 099c9e4
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 30 deletions.
93 changes: 93 additions & 0 deletions Platformio/hardware/ESP32/keyboard_ble_hal_esp32.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#if (ENABLE_KEYBOARD_BLE == 1)

#include <nvs.h>
#include <nvs_flash.h>

#include "lib/ESP32-BLE-Keyboard/BleKeyboard.h"
#include "battery_hal_esp32.h"
#include "keyboard_ble_hal_esp32.h"
Expand Down Expand Up @@ -59,7 +62,97 @@ void keyboardBLE_BLEkeyboardMessage_cb(std::string message) {
}
}

void delete_bonds_if_NimBLE_version_changed() {
// This function checks if bonds are already present when changing from NimBLE 1.4.x to 2.0.x or from 2.0.x back to 1.4.x
// In these cases, we have to delete the already existing bonds.
// Otherwise the bonds will not work (when going from 1.4.x to 2.0.x) or the ESP32 will even crash (when going from 2.0.x back to 1.4.x).
// See https://github.com/h2zero/NimBLE-Arduino/issues/740
// The name of the NVS partition and blobs used in this function can be seen here:
// <nimble/nimble/host/store/config/src/ble_store_nvs.c>
// NimBLE 1.4.x -> nimble core 1.4
// NimBLE 2.0.x -> nimble core 1.5

// startup: init flash
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
Serial.printf("nvs_flash_init() failed with error=%d, will erase flash\r\n", err);
err = nvs_flash_erase();
if (err != ESP_OK) {
Serial.printf("nvs_flash_erase() failed with error=%d; will return\r\n", err);
return;
}
err = nvs_flash_init();
if (err != ESP_OK) {
Serial.printf("nvs_flash_init() failed with error=%d, even after flash was erased; will return\r\n", err);
return;
}
}

// open partition "nimble_bond" where the bonds are stored
nvs_handle_t nimble_bond_handle;
err = nvs_open("nimble_bond", NVS_READWRITE, &nimble_bond_handle);
if (err != ESP_OK) {
Serial.printf("nvs_open 'nimble_bond' failed with error=%d, will return\r\n", err);
return;
}

size_t required_size = 0;
// Key generated during the pairing process. Present if a bond exists, used by NimBLE 1.4.x and NimBLE 2.0.x
err = nvs_get_blob(nimble_bond_handle, "peer_sec_1", NULL, &required_size);
bool bond_exists = (err == ESP_OK);
// Resolvable Private Address (RPA): Bluetooth Device Address that changes periodically.
// Only present in NimBLE 2.0.x
err = nvs_get_blob(nimble_bond_handle, "rpa_rec_1", NULL, &required_size);
bool rpa_exists = (err == ESP_OK);
// Identity Resolving Key (IRK): Key used for Address Resolution (resolves an RPA).
// Only present in NimBLE 2.0.x
err = nvs_get_blob(nimble_bond_handle, "local_irk_1", NULL, &required_size);
bool irk_exists = (err == ESP_OK);
// and just for information, what an Identity Address is:
// Identity Address: An address associated with an RPA that does not change over time. An IRK is required to resolve an RPA to its Identity Address.

// Serial.printf("'peer_sec_1' present: %s; 'rpa_rec_1' present: %s; 'local_irk_1' present: %s\r\n", bond_exists ? "yes" : "no", rpa_exists ? "yes" : "no", irk_exists ? "yes" : "no");
/*
peer_sec_1 rpa_rec_1 local_irk_1 partition 'nimble_bond' should be deleted
1.4.x, no bonds NO NO NO
1.4.x, with bonds from 1.4.x YES NO NO
1.4.x, with bonds from 2.0.x YES YES YES x (otherwise will not work)
1.4.x, with bonds from 2.0.x deleted NO NO Y/N(*) (x) (just to be save, would work without) (*)YES or NO, depending on ESP32 has rebooted at least once in 2.0.x after bond was deleted
2.0.x, no bonds NO NO YES
2.0.x, with bonds from 1.4.x YES NO YES x (otherwise will crash)
2.0.x, with bonds from 1.4.x deleted NO NO YES
2.0.x, with bonds from 2.0.x YES YES YES
*/

#if !defined(NIMBLE_ARDUINO_2_x)
// We are in NimBLE 1.4.x. Check if we downgraded from NimBLE 2.0.x
bool erase_nimble_partition = (rpa_exists || irk_exists);
if (erase_nimble_partition) {
Serial.printf("We are using NimBLE 1.4.x, but bonds from NimBLE 2.0.x are present. We have to delete all bonds, otherwise ESP32 will crash! Please bond your peers again.\r\n");
}
#else
// We are in NimBLE 2.0.x. Check if we upgraded from NimBLE 1.4.x
bool erase_nimble_partition = bond_exists && !(rpa_exists);
if (erase_nimble_partition) {
Serial.printf("We are using NimBLE 2.0.x, but bonds from NimBLE 1.4.x are present. We have to delete all bonds, otherwise they will not work! Please bond your peers again.\r\n");
}
#endif

if (erase_nimble_partition) {
nvs_erase_all(nimble_bond_handle);
nvs_commit(nimble_bond_handle);
nvs_close(nimble_bond_handle);
// ESP needs to be restarted, because NVS data is still in nimble RAM
Serial.printf(" NSV partition 'nimble_bond' was erased. Now we have to restart the ESP32 to also clear nimble RAM.\r\n");
ESP.restart();
} else {
nvs_close(nimble_bond_handle);
}
}

void init_keyboardBLE_HAL() {
delete_bonds_if_NimBLE_version_changed();

int battery_voltage;
int battery_percentage;
boolean battery_ischarging;
Expand Down
34 changes: 17 additions & 17 deletions Platformio/hardware/ESP32/lib/ESP32-BLE-Keyboard/BleKeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void BleKeyboard::begin(void)
pServer->setCallbacks(this);

hid = new NimBLEHIDDevice(pServer);
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
inputKeyboard = hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report map
outputKeyboard = hid->outputReport(KEYBOARD_ID);
inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID);
Expand All @@ -120,7 +120,7 @@ void BleKeyboard::begin(void)

outputKeyboard->setCallbacks(this);

#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
hid->manufacturer()->setValue(deviceManufacturer);

hid->pnp(0x02, vid, pid, version);
Expand All @@ -135,7 +135,7 @@ void BleKeyboard::begin(void)

NimBLEDevice::setSecurityAuth(true, true, true);

#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor));
#else
hid->setReportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor));
Expand All @@ -144,7 +144,7 @@ void BleKeyboard::begin(void)

advertising = pServer->getAdvertising();
advertising->setAppearance(HID_KEYBOARD);
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
advertising->addServiceUUID(hid->hidService()->getUUID());
advertising->setScanResponse(false);
#else
Expand Down Expand Up @@ -529,7 +529,7 @@ size_t BleKeyboard::write(const uint8_t *buffer, size_t size) {
return n;
}

#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
void BleKeyboard::onConnect(NimBLEServer* pServer) {
#else
void BleKeyboard::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
Expand All @@ -539,7 +539,7 @@ void BleKeyboard::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
std::string message = "";
char buffer[200];
if (pServer->getConnectedCount() == 1) {
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
NimBLEConnInfo connInfo = pServer->getPeerInfo(0);
#endif
sprintf(buffer, "BleKeyboard: onConnect: client %s%s, id %s%s, handle %u, isBonded %d",
Expand All @@ -560,14 +560,14 @@ void BleKeyboard::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {

}

#if defined(USE_NIMBLE_200)
#if defined(NIMBLE_ARDUINO_2_x)
void BleKeyboard::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std::string& name) {
this->connected = true;
this->_advertising = false;
std::string message = "";
char buffer[200];
if (pServer->getConnectedCount() == 1) {
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
NimBLEConnInfo connInfo = pServer->getPeerInfo(0);
#endif
sprintf(buffer, "BleKeyboard: onConnect with name: client %s%s, id %s%s, handle %u, isBonded %d, name %s",
Expand All @@ -590,7 +590,7 @@ void BleKeyboard::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std
}
#endif

#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
void BleKeyboard::onDisconnect(NimBLEServer* pServer) {
#else
void BleKeyboard::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
Expand All @@ -601,7 +601,7 @@ void BleKeyboard::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo,
if (pServer->getConnectedCount() == 0) {
sprintf(buffer, "BleKeyboard: onDisconnect: no clients connected");
} else if (pServer->getConnectedCount() == 1) {
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
NimBLEConnInfo connInfo = pServer->getPeerInfo(0);
#endif
sprintf(buffer, "BleKeyboard: onDisconnect: there is still a client connected %s%s, id %s%s, handle %u, isBonded %d. How can it be???",
Expand All @@ -622,7 +622,7 @@ void BleKeyboard::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo,

}

#if defined(USE_NIMBLE_200)
#if defined(NIMBLE_ARDUINO_2_x)
void BleKeyboard::onIdentity(NimBLEConnInfo& connInfo) {
std::string message = "";
char buffer[200];
Expand All @@ -641,7 +641,7 @@ void BleKeyboard::onIdentity(NimBLEConnInfo& connInfo) {
}
#endif

#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
void BleKeyboard::onWrite(NimBLECharacteristic* pCharacteristic) {
#else
void BleKeyboard::onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
Expand Down Expand Up @@ -702,7 +702,7 @@ void BleKeyboard::startAdvertisingForAll() {
this->prepareAdvertising();

advertising->setScanFilter(false, false);
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
advertising->setAdvertisementType(BLE_GAP_CONN_MODE_UND);
#else
advertising->setConnectableMode(BLE_GAP_CONN_MODE_UND);
Expand Down Expand Up @@ -730,7 +730,7 @@ void BleKeyboard::startAdvertisingWithWhitelist(std::string peersAllowed) {
}

advertising->setScanFilter(true, true);
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
advertising->setAdvertisementType(BLE_GAP_CONN_MODE_UND);
#else
advertising->setConnectableMode(BLE_GAP_CONN_MODE_UND);
Expand All @@ -754,7 +754,7 @@ void BleKeyboard::startAdvertisingDirected(std::string peerAddress, bool isRando
directedAddress = NimBLEAddress(peerAddress, BLE_ADDR_PUBLIC);
}
advertising->setScanFilter(false, false);
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
advertising->setAdvertisementType(BLE_GAP_CONN_MODE_DIR);
advertising->start(BLE_HS_FOREVER, nullptr, &directedAddress);
#else
Expand Down Expand Up @@ -791,7 +791,7 @@ void BleKeyboard::printConnectedClients() {

std::vector<uint16_t> m_connectedPeersVec = NimBLEDevice::getServer()->getPeerDevices();
for (std::vector<uint16_t>::iterator it = m_connectedPeersVec.begin() ; it != m_connectedPeersVec.end(); ++it) {
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
NimBLEConnInfo connInfo = NimBLEDevice::getServer()->getPeerIDInfo(*it);
#else
NimBLEConnInfo connInfo = NimBLEDevice::getServer()->getPeerInfoByHandle(*it);
Expand Down Expand Up @@ -931,7 +931,7 @@ bool BleKeyboard::forceConnectionToAddress(std::string peerAddress) {
ESP_LOGD(LOG_TAG, "BleKeyboard: already connected, no specific address was provided, nothing to do.\n");
return true;
} else {
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
NimBLEConnInfo connInfo = NimBLEDevice::getServer()->getPeerIDInfo(0);
#else
NimBLEConnInfo connInfo = NimBLEDevice::getServer()->getPeerInfoByHandle(0);
Expand Down
18 changes: 7 additions & 11 deletions Platformio/hardware/ESP32/lib/ESP32-BLE-Keyboard/BleKeyboard.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
#define USE_NIMBLE_200
// with USE_NIMBLE_200, please also change platformio.ini:
// either NimBLE 1.4.2
// // #define USE_NIMBLE_200
// h2zero/NimBLE-Arduino@^1.4.2
// ;https://github.com/h2zero/NimBLE-Arduino#master
// or NimBLE 2.0.0 (master branch)
// #define USE_NIMBLE_200
// ;h2zero/NimBLE-Arduino@^1.4.2
// https://github.com/h2zero/NimBLE-Arduino#master
// This include is only needed to determine if NimBLE 1.4.x or 2.0.x is used.
// NimBLE 2.0.x is using nimble core 1.5, and only in this version BLE_STORE_OBJ_TYPE_LOCAL_IRK is defined
#include "nimble/nimble/host/include/host/ble_store.h"
#if defined(BLE_STORE_OBJ_TYPE_LOCAL_IRK)
#define NIMBLE_ARDUINO_2_x
#endif

#ifndef ESP32_BLE_KEYBOARD_H
#define ESP32_BLE_KEYBOARD_H
Expand Down Expand Up @@ -190,7 +186,7 @@ class BleKeyboard : public Print, public NimBLEServerCallbacks, public NimBLECha
void set_product_id(uint16_t pid);
void set_version(uint16_t version);
protected:
#if !defined(USE_NIMBLE_200)
#if !defined(NIMBLE_ARDUINO_2_x)
// NimBLEServerCallbacks
virtual void onConnect(NimBLEServer* pServer) override;
virtual void onDisconnect(NimBLEServer* pServer) override;
Expand Down
3 changes: 1 addition & 2 deletions Platformio/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ lib_deps =
sparkfun/SparkFun LIS3DH Arduino Library@^1.0.3
crankyoldgit/IRremoteESP8266@^2.8.6
knolleary/PubSubClient@^2.8
; please also set #define USE_NIMBLE_200 in BleKeyboard.h
;h2zero/NimBLE-Arduino@^1.4.2
;h2zero/NimBLE-Arduino@^1.4.3
https://github.com/h2zero/NimBLE-Arduino#master
sparkfun/SparkFun MAX1704x Fuel Gauge Arduino Library@^1.0.4
;chris--a/Keypad@^3.1.1
Expand Down

0 comments on commit 099c9e4

Please sign in to comment.