mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-04 17:11:01 +00:00
Bluetooth mode unification and behavior tweaks (#1636)
* Esp32 bluetooth modes * Comment * Gutting bluetooth * Cleanup * Security * Testing * NRF bluetooth security * Reboot on saved lora or bluetooth settings * Cleanup * Fixes * Stub for platforms without screens * Fixed just-works in esp32 * Cleanup * Display device name in boot screen * Added waypoint module routing * chmod * Words * Protos * Backing out partition changes for testing * Revert "Backing out partition changes for testing" This reverts commit191ed6489c. * Chmod PR artifacts * Trying setInitialState again * Revert "Trying setInitialState again" This reverts commit703eac7277. * External notification module * Cleanup * Pin display formatting
This commit is contained in:
@@ -1,160 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "../concurrency/LockGuard.h"
|
||||
#include "../graphics/Screen.h"
|
||||
#include "../main.h"
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "configuration.h"
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
|
||||
#include <CRC32.h>
|
||||
#include <Update.h>
|
||||
|
||||
int16_t updateResultHandle = -1;
|
||||
|
||||
static CRC32 crc;
|
||||
|
||||
static uint32_t updateExpectedSize, updateActualSize;
|
||||
static uint8_t update_result;
|
||||
static uint8_t update_region;
|
||||
|
||||
static concurrency::Lock *updateLock;
|
||||
|
||||
/// Handle writes & reads to total size
|
||||
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
|
||||
// Check if there is enough to OTA Update
|
||||
chr_readwrite32le(&updateExpectedSize, ctxt);
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
|
||||
updateActualSize = 0;
|
||||
crc.reset();
|
||||
if (Update.isRunning())
|
||||
Update.abort();
|
||||
bool canBegin = Update.begin(updateExpectedSize, update_region);
|
||||
DEBUG_MSG("Setting region %d update size %u, result %d\n", update_region, updateExpectedSize, canBegin);
|
||||
if (!canBegin) {
|
||||
// Indicate failure by forcing the size to 0 (client will read it back)
|
||||
updateExpectedSize = 0;
|
||||
} else {
|
||||
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
|
||||
// talk to one service during the sw update.
|
||||
// DEBUG_MSG("FIXME, crufty shutdown of mesh bluetooth for sw update.");
|
||||
// void stopMeshBluetoothService();
|
||||
// stopMeshBluetoothService();
|
||||
|
||||
screen->startFirmwareUpdateScreen();
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we
|
||||
// are writing flash - shut the radio off during updates
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_BLOCKSIZE_FOR_BT 512
|
||||
|
||||
/// Handle writes to data
|
||||
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
|
||||
static uint8_t
|
||||
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
||||
|
||||
uint16_t len = 0;
|
||||
|
||||
auto rc = ble_hs_mbuf_to_flat(ctxt->om, data, sizeof(data), &len);
|
||||
assert(rc == 0);
|
||||
|
||||
// DEBUG_MSG("Writing %u\n", len);
|
||||
crc.update(data, len);
|
||||
Update.write(data, len);
|
||||
updateActualSize += len;
|
||||
powerFSM.trigger(EVENT_FIRMWARE_UPDATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Handle writes to crc32
|
||||
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
uint32_t expectedCRC = 0;
|
||||
chr_readwrite32le(&expectedCRC, ctxt);
|
||||
|
||||
uint32_t actualCRC = crc.finalize();
|
||||
DEBUG_MSG("expected CRC %u\n", expectedCRC);
|
||||
|
||||
uint8_t result = 0xff;
|
||||
|
||||
if (updateActualSize != updateExpectedSize) {
|
||||
DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
|
||||
result = 0xe1; // FIXME, use real error codes
|
||||
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
|
||||
{
|
||||
DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
|
||||
result = 0xe0; // FIXME, use real error codes
|
||||
} else {
|
||||
if (Update.end()) {
|
||||
if (update_region == U_SPIFFS) {
|
||||
DEBUG_MSG("Filesystem updated!\n");
|
||||
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
|
||||
} else {
|
||||
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
|
||||
}
|
||||
result = Update.getError();
|
||||
}
|
||||
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->startReceive(); // Resume radio
|
||||
|
||||
assert(updateResultHandle >= 0);
|
||||
update_result = result;
|
||||
DEBUG_MSG("BLE notify update result\n");
|
||||
auto res = ble_gattc_notify(curConnectionHandle, updateResultHandle);
|
||||
assert(res == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
return chr_readwrite8(&update_result, sizeof(update_result), ctxt);
|
||||
}
|
||||
|
||||
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
|
||||
}
|
||||
|
||||
/*
|
||||
See bluetooth-api.md
|
||||
|
||||
*/
|
||||
void reinitUpdateService()
|
||||
{
|
||||
if (!updateLock)
|
||||
updateLock = new concurrency::Lock();
|
||||
|
||||
auto res = ble_gatts_count_cfg(gatt_update_svcs); // assigns handles? see docstring for note about clearing the handle list
|
||||
// before calling SLEEP SUPPORT
|
||||
assert(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(gatt_update_svcs);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nimble/NimbleDefs.h"
|
||||
|
||||
void reinitUpdateService();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
extern const struct ble_gatt_svc_def gatt_update_svcs[];
|
||||
|
||||
extern const ble_uuid128_t update_result_uuid, update_region_uuid;
|
||||
|
||||
extern int16_t updateResultHandle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
@@ -1,222 +0,0 @@
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#include "configuration.h"
|
||||
#include "ESP32Bluetooth.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "sleep.h"
|
||||
#include "main.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
NimBLECharacteristic *fromNumCharacteristic;
|
||||
NimBLEServer *bleServer;
|
||||
|
||||
static bool passkeyShowing;
|
||||
static uint32_t doublepressed;
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum)
|
||||
{
|
||||
PhoneAPI::onNowHasData(fromRadioNum);
|
||||
|
||||
DEBUG_MSG("BLE notify fromNum\n");
|
||||
|
||||
uint8_t val[4];
|
||||
put_le32(val, fromRadioNum);
|
||||
|
||||
fromNumCharacteristic->setValue(val, sizeof(val));
|
||||
fromNumCharacteristic->notify();
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected()
|
||||
{
|
||||
return bleServer && bleServer->getConnectedCount() > 0;
|
||||
}
|
||||
};
|
||||
|
||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
|
||||
class ESP32BluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
||||
{
|
||||
virtual void onWrite(NimBLECharacteristic *pCharacteristic) {
|
||||
DEBUG_MSG("To Radio onwrite\n");
|
||||
auto val = pCharacteristic->getValue();
|
||||
|
||||
bluetoothPhoneAPI->handleToRadio(val.data(), val.length());
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32BluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
||||
{
|
||||
virtual void onRead(NimBLECharacteristic *pCharacteristic) {
|
||||
DEBUG_MSG("From Radio onread\n");
|
||||
uint8_t fromRadioBytes[FromRadio_size];
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
|
||||
|
||||
std::string fromRadioByteString(fromRadioBytes, fromRadioBytes + numBytes);
|
||||
|
||||
pCharacteristic->setValue(fromRadioByteString);
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32BluetoothServerCallback : public NimBLEServerCallbacks
|
||||
{
|
||||
virtual uint32_t onPassKeyRequest() {
|
||||
uint32_t passkey = config.bluetooth.fixed_pin;
|
||||
|
||||
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
|
||||
DEBUG_MSG("User has set BLE pairing mode to fixed-pin\n");
|
||||
config.bluetooth.mode = Config_BluetoothConfig_PairingMode_FixedPin;
|
||||
nodeDB.saveToDisk();
|
||||
} else if (config.bluetooth.mode == Config_BluetoothConfig_PairingMode_RandomPin) {
|
||||
DEBUG_MSG("Using random passkey\n");
|
||||
// This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
|
||||
passkey = random(100000, 999999);
|
||||
}
|
||||
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", passkey);
|
||||
|
||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||
screen->startBluetoothPinScreen(passkey);
|
||||
passkeyShowing = true;
|
||||
|
||||
return passkey;
|
||||
}
|
||||
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc)
|
||||
{
|
||||
DEBUG_MSG("BLE authentication complete\n");
|
||||
|
||||
if (passkeyShowing) {
|
||||
passkeyShowing = false;
|
||||
screen->stopBluetoothPinScreen();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc *desc)
|
||||
{
|
||||
DEBUG_MSG("BLE disconnect\n");
|
||||
}
|
||||
};
|
||||
|
||||
static ESP32BluetoothToRadioCallback *toRadioCallbacks;
|
||||
static ESP32BluetoothFromRadioCallback *fromRadioCallbacks;
|
||||
|
||||
void ESP32Bluetooth::shutdown()
|
||||
{
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
DEBUG_MSG("Disable bluetooth\n");
|
||||
//Bluefruit.Advertising.stop();
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->reset();
|
||||
pAdvertising->stop();
|
||||
}
|
||||
|
||||
bool ESP32Bluetooth::isActive()
|
||||
{
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
return bleServer && (bleServer->getConnectedCount() > 0 || pAdvertising->isAdvertising());
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::setup()
|
||||
{
|
||||
DEBUG_MSG("Initialise the ESP32 bluetooth module\n");
|
||||
|
||||
NimBLEDevice::init(getDeviceName());
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
|
||||
// FIXME fails in iOS
|
||||
if (config.bluetooth.mode == Config_BluetoothConfig_PairingMode_NoPin) {
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_NO_INPUT_OUTPUT);
|
||||
NimBLEDevice::setSecurityAuth(true, false, true);
|
||||
}
|
||||
else {
|
||||
NimBLEDevice::setSecurityAuth(true, true, true);
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
||||
}
|
||||
bleServer = NimBLEDevice::createServer();
|
||||
|
||||
ESP32BluetoothServerCallback *serverCallbacks = new ESP32BluetoothServerCallback();
|
||||
bleServer->setCallbacks(serverCallbacks, true);
|
||||
|
||||
setupService();
|
||||
startAdvertising();
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::setupService()
|
||||
{
|
||||
NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID);
|
||||
|
||||
//define the characteristics that the app is looking for
|
||||
NimBLECharacteristic *ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLECharacteristic *FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
|
||||
fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
|
||||
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
|
||||
toRadioCallbacks = new ESP32BluetoothToRadioCallback();
|
||||
ToRadioCharacteristic->setCallbacks(toRadioCallbacks);
|
||||
|
||||
fromRadioCallbacks = new ESP32BluetoothFromRadioCallback();
|
||||
FromRadioCharacteristic->setCallbacks(fromRadioCallbacks);
|
||||
|
||||
bleService->start();
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::startAdvertising()
|
||||
{
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->reset();
|
||||
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
||||
pAdvertising->start(0);
|
||||
}
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
//blebas.write(level);
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::clearBonds()
|
||||
{
|
||||
DEBUG_MSG("Clearing bluetooth bonds!\n");
|
||||
NimBLEDevice::deleteAllBonds();
|
||||
}
|
||||
|
||||
void clearNVS()
|
||||
{
|
||||
NimBLEDevice::deleteAllBonds();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void disablePin()
|
||||
{
|
||||
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
|
||||
// keep track of when it was pressed, so we know it was within X seconds
|
||||
|
||||
// Flash the LED
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
delay(100);
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
delay(100);
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
|
||||
doublepressed = millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#pragma once
|
||||
|
||||
class ESP32Bluetooth
|
||||
{
|
||||
public:
|
||||
void setup();
|
||||
void shutdown();
|
||||
void clearBonds();
|
||||
bool isActive();
|
||||
|
||||
private:
|
||||
void setupService();
|
||||
void startAdvertising();
|
||||
};
|
||||
|
||||
void setBluetoothEnable(bool on);
|
||||
void clearNVS();
|
||||
void disablePin();
|
||||
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
|
||||
|
||||
// "cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"
|
||||
const ble_uuid128_t update_service_uuid =
|
||||
BLE_UUID128_INIT(0x30, 0xee, 0x44, 0x31, 0x2e, 0x44, 0xbb, 0xbd, 0x0d, 0x4c, 0x4c, 0xa8, 0x0b, 0x9a, 0x0b, 0xcb);
|
||||
|
||||
// "e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e" write|read
|
||||
const ble_uuid128_t update_size_uuid =
|
||||
BLE_UUID128_INIT(0x1e, 0x8e, 0xea, 0xdb, 0xe1, 0xf0, 0xa1, 0x95, 0x6f, 0x4a, 0x01, 0xa3, 0xc0, 0xd9, 0x4d, 0xe7);
|
||||
|
||||
// "e272ebac-d463-4b98-bc84-5cc1a39ee517" write
|
||||
const ble_uuid128_t update_data_uuid =
|
||||
BLE_UUID128_INIT(0x17, 0xe5, 0x9e, 0xa3, 0xc1, 0x5c, 0x84, 0xbc, 0x98, 0x4b, 0x63, 0xd4, 0xac, 0xeb, 0x72, 0xe2);
|
||||
|
||||
// "4826129c-c22a-43a3-b066-ce8f0d5bacc6" write
|
||||
const ble_uuid128_t update_crc32_uuid =
|
||||
BLE_UUID128_INIT(0xc6, 0xac, 0x5b, 0x0d, 0x8f, 0xce, 0x66, 0xb0, 0xa3, 0x43, 0x2a, 0xc2, 0x9c, 0x12, 0x26, 0x48);
|
||||
|
||||
// "5e134862-7411-4424-ac4a-210937432c77" read|notify
|
||||
const ble_uuid128_t update_result_uuid =
|
||||
BLE_UUID128_INIT(0x77, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
|
||||
|
||||
// "5e134862-7411-4424-ac4a-210937432c67" write
|
||||
const ble_uuid128_t update_region_uuid =
|
||||
BLE_UUID128_INIT(0x67, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
|
||||
|
||||
const struct ble_gatt_svc_def gatt_update_svcs[] = {
|
||||
{
|
||||
/*** Service: Security test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &update_service_uuid.u,
|
||||
.characteristics =
|
||||
(struct ble_gatt_chr_def[]){{
|
||||
.uuid = &update_size_uuid.u,
|
||||
.access_cb = update_size_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_READ_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_data_uuid.u,
|
||||
.access_cb = update_data_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_crc32_uuid.u,
|
||||
.access_cb = update_crc32_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_result_uuid.u,
|
||||
.access_cb = update_result_callback,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
|
||||
},
|
||||
{
|
||||
.uuid = &update_region_uuid.u,
|
||||
.access_cb = update_region_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
0, /* No more characteristics in this service. */
|
||||
}},
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
@@ -6,6 +6,9 @@
|
||||
// defaults for ESP32 architecture
|
||||
//
|
||||
|
||||
#ifndef HAS_BLUETOOTH
|
||||
#define HAS_BLUETOOTH 1
|
||||
#endif
|
||||
#ifndef HAS_WIFI
|
||||
#define HAS_WIFI 1
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
#include "ESP32Bluetooth.h"
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#else
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
@@ -19,41 +14,26 @@
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
ESP32Bluetooth *esp32Bluetooth;
|
||||
#endif
|
||||
NimbleBluetooth *nimbleBluetooth;
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
static void printBLEinfo() {
|
||||
int dev_num = esp_ble_get_bond_device_num();
|
||||
|
||||
esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
|
||||
esp_ble_get_bond_device_list(&dev_num, dev_list);
|
||||
for (int i = 0; i < dev_num; i++) {
|
||||
// esp_ble_remove_bond_device(dev_list[i].bd_addr);
|
||||
}
|
||||
|
||||
} */
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
void setBluetoothEnable(bool on) {
|
||||
|
||||
if (!isWifiAvailable()) {
|
||||
if (!esp32Bluetooth) {
|
||||
esp32Bluetooth = new ESP32Bluetooth();
|
||||
if (!isWifiAvailable() && config.bluetooth.enabled == true) {
|
||||
if (!nimbleBluetooth) {
|
||||
nimbleBluetooth = new NimbleBluetooth();
|
||||
}
|
||||
if (on && !esp32Bluetooth->isActive()) {
|
||||
esp32Bluetooth->setup();
|
||||
if (on && !nimbleBluetooth->isActive()) {
|
||||
nimbleBluetooth->setup();
|
||||
} else {
|
||||
esp32Bluetooth->shutdown();
|
||||
nimbleBluetooth->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void esp32Setup()
|
||||
{
|
||||
@@ -123,7 +103,6 @@ Periodic axpDebugOutput(axpDebugRead);
|
||||
void esp32Loop()
|
||||
{
|
||||
esp_task_wdt_reset(); // service our app level watchdog
|
||||
//loopBLE();
|
||||
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <Arduino.h>
|
||||
#include "configuration.h"
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "main.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
@@ -22,7 +24,7 @@ static BLEDfu bledfu; // DFU software update helper service
|
||||
static uint8_t fromRadioBytes[FromRadio_size];
|
||||
static uint8_t toRadioBytes[ToRadio_size];
|
||||
|
||||
static bool bleConnected;
|
||||
static uint16_t connectionHandle;
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
@@ -39,13 +41,14 @@ class BluetoothPhoneAPI : public PhoneAPI
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override {
|
||||
return bleConnected;
|
||||
BLEConnection *connection = Bluefruit.Connection(connectionHandle);
|
||||
return connection->connected();
|
||||
}
|
||||
};
|
||||
|
||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
void connect_callback(uint16_t conn_handle)
|
||||
void onConnect(uint16_t conn_handle)
|
||||
{
|
||||
// Get the reference to current connection
|
||||
BLEConnection *connection = Bluefruit.Connection(conn_handle);
|
||||
@@ -54,7 +57,7 @@ void connect_callback(uint16_t conn_handle)
|
||||
connection->getPeerName(central_name, sizeof(central_name));
|
||||
|
||||
DEBUG_MSG("BLE Connected to %s\n", central_name);
|
||||
bleConnected = true;
|
||||
// bluetoothPhoneAPI->setInitialState();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,15 +65,12 @@ void connect_callback(uint16_t conn_handle)
|
||||
* @param conn_handle connection where this event happens
|
||||
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
|
||||
*/
|
||||
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
|
||||
void onDisconnect(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
// FIXME - we currently assume only one active connection
|
||||
bleConnected = false;
|
||||
|
||||
DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason);
|
||||
}
|
||||
|
||||
void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
void onCCCD(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
{
|
||||
// Display the raw request packet
|
||||
DEBUG_MSG("CCCD Updated: %u\n", cccd_value);
|
||||
@@ -126,7 +126,7 @@ static void authorizeRead(uint16_t conn_hdl)
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
void onFromRadio(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
if (request->offset == 0) {
|
||||
// If the read is long, we will get multiple authorize invocations - we only populate data on the first
|
||||
@@ -141,7 +141,7 @@ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||
void onToRadio(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||
{
|
||||
DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len);
|
||||
|
||||
@@ -151,7 +151,7 @@ void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, ui
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
DEBUG_MSG("fromNumAuthorizeCb\n");
|
||||
|
||||
@@ -168,39 +168,37 @@ void setupMeshService(void)
|
||||
// any characteristic(s) within that service definition.. Calling .begin() on
|
||||
// a BLECharacteristic will cause it to be added to the last BLEService that
|
||||
// was 'begin()'ed!
|
||||
|
||||
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
|
||||
fromNum.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!!
|
||||
fromNum.setFixedLen(0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
|
||||
fromNum.setMaxLen(4);
|
||||
fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
|
||||
fromNum.setCccdWriteCallback(onCCCD); // Optionally capture CCCD updates
|
||||
// We don't yet need to hook the fromNum auth callback
|
||||
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
|
||||
fromNum.write32(0); // Provide default fromNum of 0
|
||||
fromNum.begin();
|
||||
|
||||
fromRadio.setProperties(CHR_PROPS_READ);
|
||||
fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this!
|
||||
// fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this!
|
||||
fromRadio.setMaxLen(sizeof(fromRadioBytes));
|
||||
fromRadio.setReadAuthorizeCallback(
|
||||
fromRadioAuthorizeCb,
|
||||
onFromRadio,
|
||||
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
|
||||
// for two copies
|
||||
fromRadio.begin();
|
||||
|
||||
toRadio.setProperties(CHR_PROPS_WRITE);
|
||||
toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this!
|
||||
// toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this!
|
||||
toRadio.setFixedLen(0);
|
||||
toRadio.setMaxLen(512);
|
||||
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
|
||||
// We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
toRadio.setWriteCallback(toRadioWriteCb, false);
|
||||
toRadio.setWriteCallback(onToRadio, false);
|
||||
toRadio.begin();
|
||||
}
|
||||
|
||||
// FIXME, turn off soft device access for debugging
|
||||
static bool isSoftDeviceAllowed = true;
|
||||
static uint32_t configuredPasskey;
|
||||
|
||||
void NRF52Bluetooth::shutdown()
|
||||
{
|
||||
@@ -211,9 +209,14 @@ void NRF52Bluetooth::shutdown()
|
||||
|
||||
void NRF52Bluetooth::setup()
|
||||
{
|
||||
// Uncomment for testing
|
||||
// Bluefruit.Periph.clearBonds();
|
||||
// Bluefruit.Central.clearBonds();
|
||||
|
||||
// Initialise the Bluefruit module
|
||||
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n");
|
||||
Bluefruit.autoConnLed(false);
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.begin();
|
||||
|
||||
// Clear existing data.
|
||||
@@ -221,12 +224,29 @@ void NRF52Bluetooth::setup()
|
||||
Bluefruit.Advertising.clearData();
|
||||
Bluefruit.ScanResponse.clearData();
|
||||
|
||||
if (config.bluetooth.mode != Config_BluetoothConfig_PairingMode_NoPin) {
|
||||
configuredPasskey = config.bluetooth.mode == Config_BluetoothConfig_PairingMode_FixedPin ?
|
||||
config.bluetooth.fixed_pin : random(100000, 999999);
|
||||
auto pinString = std::to_string(configuredPasskey);
|
||||
DEBUG_MSG("Bluetooth pin set to '%i'\n", configuredPasskey);
|
||||
Bluefruit.Security.setPIN(pinString.c_str());
|
||||
Bluefruit.Security.setIOCaps(true, false, false);
|
||||
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey);
|
||||
Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted);
|
||||
Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured);
|
||||
meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
}
|
||||
else {
|
||||
Bluefruit.Security.setIOCaps(false, false, false);
|
||||
meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN);
|
||||
}
|
||||
|
||||
// Set the advertised device name (keep it short!)
|
||||
Bluefruit.setName(getDeviceName());
|
||||
|
||||
// Set the connect/disconnect callback handlers
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
Bluefruit.Periph.setConnectCallback(onConnect);
|
||||
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
DEBUG_MSG("Configuring the Device Information Service\n");
|
||||
@@ -251,7 +271,6 @@ void NRF52Bluetooth::setup()
|
||||
// Setup the advertising packet(s)
|
||||
DEBUG_MSG("Setting up the advertising payload(s)\n");
|
||||
startAdv();
|
||||
|
||||
DEBUG_MSG("Advertising\n");
|
||||
}
|
||||
}
|
||||
@@ -271,3 +290,41 @@ void NRF52Bluetooth::clearBonds()
|
||||
Bluefruit.Periph.clearBonds();
|
||||
Bluefruit.Central.clearBonds();
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
|
||||
{
|
||||
DEBUG_MSG("BLE connection secured\n");
|
||||
BLEConnection* connection = Bluefruit.Connection(conn_handle);
|
||||
|
||||
if (!connection->secured())
|
||||
{
|
||||
connection->requestPairing();
|
||||
}
|
||||
}
|
||||
|
||||
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
||||
{
|
||||
DEBUG_MSG("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey+3);
|
||||
screen->startBluetoothPinScreen(configuredPasskey);
|
||||
|
||||
if (match_request)
|
||||
{
|
||||
uint32_t start_time = millis();
|
||||
while(millis() < start_time + 30000)
|
||||
{
|
||||
if (!Bluefruit.connected(conn_handle)) break;
|
||||
}
|
||||
}
|
||||
DEBUG_MSG("BLE passkey pairing: match_request=%i\n", match_request);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status)
|
||||
{
|
||||
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
|
||||
DEBUG_MSG("BLE pairing success\n");
|
||||
else
|
||||
DEBUG_MSG("BLE pairing failed\n");
|
||||
|
||||
screen->stopBluetoothPinScreen();
|
||||
}
|
||||
|
||||
@@ -6,5 +6,10 @@ class NRF52Bluetooth
|
||||
void setup();
|
||||
void shutdown();
|
||||
void clearBonds();
|
||||
};
|
||||
|
||||
private:
|
||||
static void onConnectionSecured(uint16_t conn_handle);
|
||||
void convertToUint8(uint8_t target[4], uint32_t source);
|
||||
static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request);
|
||||
static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
//
|
||||
// defaults for NRF52 architecture
|
||||
//
|
||||
|
||||
#ifndef HAS_BLUETOOTH
|
||||
#define HAS_BLUETOOTH 1
|
||||
#endif
|
||||
#ifndef HAS_SCREEN
|
||||
#define HAS_SCREEN 1
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <stdio.h>
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
// #include <Adafruit_USBD_Device.h>
|
||||
#include "NodeDB.h"
|
||||
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "error.h"
|
||||
@@ -68,7 +69,7 @@ static const bool useSoftDevice = true; // Set to false for easier debugging
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
if (on != bleOn) {
|
||||
if (on != bleOn && config.bluetooth.enabled == true) {
|
||||
if (on) {
|
||||
if (!nrf52Bluetooth) {
|
||||
if (!useSoftDevice)
|
||||
@@ -81,9 +82,8 @@ void setBluetoothEnable(bool on)
|
||||
initBrownout();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nrf52Bluetooth)
|
||||
nrf52Bluetooth->shutdown();
|
||||
} else if (nrf52Bluetooth) {
|
||||
nrf52Bluetooth->shutdown();
|
||||
}
|
||||
bleOn = on;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user