Merge pull request #1273 from joshpirihi/master

NimBLE API Implementation
This commit is contained in:
Jm Casler 2022-03-06 17:48:14 -08:00 committed by GitHub
commit 61c2e58479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 388 additions and 9 deletions

View File

@ -131,15 +131,16 @@ debug_init_break = tbreak setup
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
# -DUSE_NEW_ESP32_BLUETOOTH will enable the new NimBLE C++ api
build_flags =
${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DAXP_DEBUG_PORT=Serial #-DUSE_NEW_ESP32_BLUETOOTH
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
h2zero/NimBLE-Arduino@1.3.6
h2zero/NimBLE-Arduino@1.3.7
tobozo/ESP32-targz@^1.1.4
arduino-libraries/NTPClient#531eff39d9fbc831f3d03f706a161739203fbe2a
lorol/LittleFS_esp32@^1.0.6

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include <Arduino.h>
#include "../concurrency/LockGuard.h"
@ -154,3 +156,5 @@ void reinitUpdateService()
res = ble_gatts_add_svcs(gatt_update_svcs);
assert(res == 0);
}
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include "nimble/NimbleDefs.h"
@ -22,4 +24,6 @@ extern int16_t updateResultHandle;
#ifdef __cplusplus
};
#endif
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -0,0 +1,262 @@
#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>
//static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
//static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
//static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
//static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
//static BLEDis bledis; // DIS (Device Information Service) helper class instance
//static BLEBas blebas; // BAS (Battery Service) helper class instance
//static BLEDfu bledfu; // DFU software update helper service
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
static uint8_t fromRadioBytes[FromRadio_size];
static uint8_t toRadioBytes[ToRadio_size];
static bool bleConnected;
NimBLECharacteristic *FromNumCharacteristic;
NimBLEServer *bleServer;
static bool passkeyShowing;
static uint32_t doublepressed;
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
DEBUG_MSG("BLE notify fromNum\n");
//fromNum.notify32(fromRadioNum);
uint8_t val[4];
put_le32(val, fromRadioNum);
std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
FromNumCharacteristic->setValue(fromNumByteString);
FromNumCharacteristic->notify();
}
/// Check the current underlying physical link to see if the client is currently connected
bool BluetoothPhoneAPI::checkIsConnected() {
if (bleServer && bleServer->getConnectedCount() > 0) {
return true;
}
return false;
}
PhoneAPI *bluetoothPhoneAPI;
class ESP32BluetoothToRadioCallback : public NimBLECharacteristicCallbacks {
virtual void onWrite(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("To Radio onwrite\n");
auto valueString = pCharacteristic->getValue();
bluetoothPhoneAPI->handleToRadio(reinterpret_cast<const uint8_t*>(&valueString[0]), pCharacteristic->getDataLength());
}
};
class ESP32BluetoothFromRadioCallback : public NimBLECharacteristicCallbacks {
virtual void onRead(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("From Radio onread\n");
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 = 0;
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
DEBUG_MSG("User has overridden passkey\n");
passkey = defaultBLEPin;
} else {
DEBUG_MSG("Using random passkey\n");
passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
}
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();
}
}
};
static ESP32BluetoothToRadioCallback *toRadioCallbacks;
static ESP32BluetoothFromRadioCallback *fromRadioCallbacks;
void ESP32Bluetooth::shutdown()
{
// Shutdown bluetooth for minimum power draw
DEBUG_MSG("Disable bluetooth\n");
//Bluefruit.Advertising.stop();
}
void ESP32Bluetooth::setup()
{
// Initialise the Bluefruit module
DEBUG_MSG("Initialise the ESP32 bluetooth module\n");
//Bluefruit.autoConnLed(false);
//Bluefruit.begin();
// 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);
// Configure and Start the Device Information Service
DEBUG_MSG("Configuring the Device Information Service\n");
// FIXME, we should set a mfg string based on our HW_VENDOR enum
// bledis.setManufacturer(HW_VENDOR);
//bledis.setModel(optstr(HW_VERSION));
//bledis.setFirmwareRev(optstr(APP_VERSION));
//bledis.begin();
// Start the BLE Battery Service and set it to 100%
//DEBUG_MSG("Configuring the Battery Service\n");
//blebas.begin();
//blebas.write(0); // Unknown battery level for now
//bledfu.begin(); // Install the DFU helper
// Setup the Heart Rate Monitor service using
// BLEService and BLECharacteristic classes
DEBUG_MSG("Configuring the Mesh bluetooth service\n");
//setupMeshService();
// Supposedly debugging works with soft device if you disable advertising
//if (isSoftDeviceAllowed) {
// Setup the advertising packet(s)
// DEBUG_MSG("Setting up the advertising payload(s)\n");
// startAdv();
// DEBUG_MSG("Advertising\n");
//}
//NimBLEDevice::deleteAllBonds();
NimBLEDevice::init("Meshtastic_1234");
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
NimBLEDevice::setSecurityAuth(true, true, true);
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
bleServer = NimBLEDevice::createServer();
ESP32BluetoothServerCallback *serverCallbacks = new ESP32BluetoothServerCallback();
bleServer->setCallbacks(serverCallbacks);
NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID);
//NimBLECharacteristic *pNonSecureCharacteristic = bleService->createCharacteristic("1234", NIMBLE_PROPERTY::READ );
//NimBLECharacteristic *pSecureCharacteristic = bleService->createCharacteristic("1235", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::READ_AUTHEN);
//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);
//uint8_t val[4];
//uint32_t zero = 0;
//put_le32(val, zero);
//std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
//FromNumCharacteristic->setValue(fromNumByteString);
bleService->start();
//pNonSecureCharacteristic->setValue("Hello Non Secure BLE");
//pSecureCharacteristic->setValue("Hello Secure BLE");
//FromRadioCharacteristic->setValue("FromRadioString");
//ToRadioCharacteristic->setCallbacks()
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
pAdvertising->start();
}
/// 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");
//bond_print_list(BLE_GAP_ROLE_PERIPH);
//bond_print_list(BLE_GAP_ROLE_CENTRAL);
//Bluefruit.Periph.clearBonds();
//Bluefruit.Central.clearBonds();
}
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

View File

@ -0,0 +1,33 @@
#ifdef USE_NEW_ESP32_BLUETOOTH
#pragma once
extern uint16_t fromNumValHandle;
class BluetoothPhoneAPI : public PhoneAPI
{
protected:
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum) override;
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
};
extern PhoneAPI *bluetoothPhoneAPI;
class ESP32Bluetooth
{
public:
void setup();
void shutdown();
void clearBonds();
};
void setBluetoothEnable(bool on);
void clearNVS();
void disablePin();
#endif

View File

@ -1,3 +1,4 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "BluetoothSoftwareUpdate.h"
// NRF52 wants these constants as byte arrays
@ -68,3 +69,5 @@ const struct ble_gatt_svc_def gatt_update_svcs[] = {
0, /* No more services. */
},
};
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -3,7 +3,13 @@
#include "configuration.h"
#include "esp_task_wdt.h"
#include "main.h"
#ifdef USE_NEW_ESP32_BLUETOOTH
#include "ESP32Bluetooth.h"
#else
#include "nimble/BluetoothUtil.h"
#endif
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
@ -12,6 +18,10 @@
#include <nvs.h>
#include <nvs_flash.h>
#ifdef USE_NEW_ESP32_BLUETOOTH
ESP32Bluetooth *esp32Bluetooth;
#endif
void getMacAddr(uint8_t *dmac)
{
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
@ -28,6 +38,19 @@ static void printBLEinfo() {
}
} */
#ifdef USE_NEW_ESP32_BLUETOOTH
void setBluetoothEnable(bool on) {
if (!esp32Bluetooth) {
esp32Bluetooth = new ESP32Bluetooth();
}
if (on) {
esp32Bluetooth->setup();
} else {
esp32Bluetooth->shutdown();
}
}
#endif
void esp32Setup()
{
@ -92,11 +115,12 @@ uint32_t axpDebugRead()
Periodic axpDebugOutput(axpDebugRead);
#endif
/// loop code specific to ESP32 targets
void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
loopBLE();
//loopBLE();
// for debug printing
// radio.radioIf.canSleep();

View File

@ -30,8 +30,14 @@
#include "mesh/http/WiFiAPClient.h"
#ifndef NO_ESP32
#include "mesh/http/WebServer.h"
#include "nimble/BluetoothUtil.h"
#include "mesh/http/WebServer.h"
#ifdef USE_NEW_ESP32_BLUETOOTH
#include "esp32/ESP32Bluetooth.h"
#else
#include "nimble/BluetoothUtil.h"
#endif
#endif
#if defined(HAS_WIFI) || defined(PORTDUINO)

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h"
#include "NimbleBluetoothAPI.h"
@ -23,6 +25,8 @@ static uint32_t doublepressed;
static bool bluetoothActive;
//put the wider device into a bluetooth pairing mode, and show the pin on screen.
//called in this file only
static void startCb(uint32_t pin)
{
pinShowing = true;
@ -30,6 +34,8 @@ static void startCb(uint32_t pin)
screen->startBluetoothPinScreen(pin);
};
//pairing has ended
//called in this file only
static void stopCb()
{
if (pinShowing) {
@ -52,6 +58,8 @@ void updateBatteryLevel(uint8_t level)
// FIXME
}
//shutdown the bluetooth and tear down all the data structures. to prevent memory leaks
//called here only
void deinitBLE()
{
if (bluetoothActive) {
@ -85,6 +93,7 @@ void loopBLE()
extern "C" void ble_store_config_init(void);
/// Print a macaddr - bytes are sometimes stored in reverse order
//called here only
static void print_addr(const uint8_t v[], bool isReversed = true)
{
const int macaddrlen = 6;
@ -96,6 +105,7 @@ static void print_addr(const uint8_t v[], bool isReversed = true)
/**
* Logs information about a connection to the console.
* called here only
*/
static void print_conn_desc(struct ble_gap_conn_desc *desc)
{
@ -260,6 +270,8 @@ static int gap_event(struct ble_gap_event *event, void *arg)
* Enables advertising with the following parameters:
* o General discoverable mode.
* o Undirected connectable mode.
*
* Called here only
*/
static void advertise(void)
{
@ -324,12 +336,16 @@ static void advertise(void)
}
}
//callback
//doesn't do anything
static void on_reset(int reason)
{
// 19 == BLE_HS_ETIMEOUT_HCI
DEBUG_MSG("Resetting state; reason=%d\n", reason);
}
//callback
//
static void on_sync(void)
{
int rc;
@ -356,6 +372,7 @@ static void on_sync(void)
advertise();
}
//do the bluetooth tasks
static void ble_host_task(void *param)
{
DEBUG_MSG("BLE task running\n");
@ -366,6 +383,7 @@ static void ble_host_task(void *param)
nimble_port_freertos_deinit(); // delete the task
}
//saves the stream handles when characteristics are successfully registered
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
@ -405,6 +423,8 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
*
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
* will be written into the variable.
*
* used a few places
*/
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt)
{
@ -637,4 +657,6 @@ void updateBatteryLevel(uint8_t level)
BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION),
optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
#endif
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include <functional>
@ -28,4 +30,6 @@ int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt);
/**
* A helper for readwrite access to an array of bytes (with no endian conversion)
*/
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt);
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt);
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "NimbleBluetoothAPI.h"
#include "PhoneAPI.h"
#include "configuration.h"
@ -69,3 +71,5 @@ int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt
{
return chr_readwrite32le(&fromNum, ctxt);
}
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include "PhoneAPI.h"
@ -17,3 +19,5 @@ protected:
};
extern PhoneAPI *bluetoothPhoneAPI;
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "NimbleDefs.h"
// NRF52 wants these constants as byte arrays
@ -44,3 +46,5 @@ const struct ble_gatt_svc_def gatt_svr_svcs[] = {
0, /* No more services. */
},
};
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@ -1,3 +1,5 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
// Keep nimble #defs from messing up the build
@ -28,4 +30,6 @@ extern const ble_uuid128_t mesh_service_uuid, fromnum_uuid;
#ifdef __cplusplus
};
#endif
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH