From ece75d1d7fe81b2b44f409361bb06b19f971e2b2 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sat, 18 Jul 2020 16:25:53 -0700 Subject: [PATCH 01/25] make PSRAM optional - new flag in ESPIDF - fix #293 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index c5aa14880..179fc8166 100644 --- a/platformio.ini +++ b/platformio.ini @@ -90,7 +90,7 @@ build_flags = # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt platform_packages = - framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#7a78d82f1b5cf64715a14d2f096b8dd775948ac1 + framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#b7f106cd11a04573b902228ea97025c8b5814dd9 ; The 1.0 release of the TBEAM board [env:tbeam] From ec082b7c9aae2cfe83931faa4c3290ac0f133af7 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sat, 18 Jul 2020 16:26:03 -0700 Subject: [PATCH 02/25] 0.8.2 --- bin/version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/version.sh b/bin/version.sh index bc2cd88af..836fd5aa1 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=0.8.1 \ No newline at end of file +export VERSION=0.8.2 \ No newline at end of file From 6aa28f55ddc935f4c157b01edcbf6e735ef39ed0 Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 21 Jul 2020 11:16:14 -0700 Subject: [PATCH 03/25] WIP stubify to get app building without CONFIG_BLUEDROID (BLE disabled) --- docs/software/esp32-arduino-build-notes.md | 9 +++++++- platformio.ini | 14 ++++++------ src/esp32/BluetoothSoftwareUpdate.cpp | 9 +++++--- src/esp32/BluetoothSoftwareUpdate.h | 6 +++++- src/esp32/BluetoothUtil.cpp | 11 ++++++++++ src/esp32/BluetoothUtil.h | 15 +++++++------ src/esp32/MeshBluetoothService.cpp | 25 ++++++++++++++++------ src/esp32/MeshBluetoothService.h | 11 +++++----- src/esp32/main-esp32.cpp | 5 ++--- 9 files changed, 70 insertions(+), 35 deletions(-) diff --git a/docs/software/esp32-arduino-build-notes.md b/docs/software/esp32-arduino-build-notes.md index b9fd68505..94b64f621 100644 --- a/docs/software/esp32-arduino-build-notes.md +++ b/docs/software/esp32-arduino-build-notes.md @@ -12,5 +12,12 @@ you'll automatically get our fixed libraries. https://docs.espressif.com/projects/esp-idf/en/release-v3.3/get-started/linux-setup.html kevinh@kevin-server:~/development/meshtastic/esp32-arduino-lib-builder\$ python /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/esp-idf/components/esptool*py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/build/bootloader/bootloader.bin cp -a out/tools/sdk/* components/arduino/tools/sdk - cp -ar components/arduino/* ~/.platformio/packages/framework-arduinoespressif32@src-fba9d33740f719f712e9f8b07da6ea13/ + cp -ar components/arduino/* ~/.platformio/packages/framework-arduinoespressif32 + + /// @src-fba9d33740f719f712e9f8b07da6ea13/ + + or + + cp -ar out/tools/sdk/* ~/.platformio/packages/framework-arduinoespressif32/tools/sdk + ``` diff --git a/platformio.ini b/platformio.ini index b7343e9be..bbf8ffbde 100644 --- a/platformio.ini +++ b/platformio.ini @@ -37,13 +37,6 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n -DAPP_VERSION=${sysenv.APP_VERSION} -DHW_VERSION=${sysenv.HW_VERSION} -; not needed included in ttgo-t-beam board file -; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram -; -DBOARD_HAS_PSRAM -; -mfix-esp32-psram-cache-issue - -; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - ; leave this commented out to avoid breaking Windows ;upload_port = /dev/ttyUSB0 ;monitor_port = /dev/ttyUSB0 @@ -92,6 +85,13 @@ lib_ignore = segger_rtt platform_packages = framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#b7f106cd11a04573b902228ea97025c8b5814dd9 +; not needed included in ttgo-t-beam board file +; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram +; -DBOARD_HAS_PSRAM +; -mfix-esp32-psram-cache-issue + +; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + ; The 1.0 release of the TBEAM board [env:tbeam] extends = esp32_base diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 3b455b56a..a1143e964 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -1,6 +1,5 @@ #include "BluetoothSoftwareUpdate.h" #include "BluetoothUtil.h" -#include "CallbackCharacteristic.h" #include "RadioLibInterface.h" #include "configuration.h" #include "../concurrency/LockGuard.h" @@ -11,7 +10,9 @@ #include #include -//using namespace meshtastic; +#ifdef CONFIG_BLUEDROID_ENABLED + +#include "CallbackCharacteristic.h" CRC32 crc; uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) @@ -176,4 +177,6 @@ void destroyUpdateService() assert(resultC); resultC = NULL; -} \ No newline at end of file +} + +#endif diff --git a/src/esp32/BluetoothSoftwareUpdate.h b/src/esp32/BluetoothSoftwareUpdate.h index 60517a7f2..80b32ffc0 100644 --- a/src/esp32/BluetoothSoftwareUpdate.h +++ b/src/esp32/BluetoothSoftwareUpdate.h @@ -5,7 +5,11 @@ #include #include +#ifdef CONFIG_BLUEDROID_ENABLED + BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion); void destroyUpdateService(); -void bluetoothRebootCheck(); \ No newline at end of file +void bluetoothRebootCheck(); + +#endif \ No newline at end of file diff --git a/src/esp32/BluetoothUtil.cpp b/src/esp32/BluetoothUtil.cpp index 03b7c974c..cc2e34225 100644 --- a/src/esp32/BluetoothUtil.cpp +++ b/src/esp32/BluetoothUtil.cpp @@ -6,6 +6,8 @@ #include #include +#ifdef CONFIG_BLUEDROID_ENABLED + SimpleAllocator btPool; bool _BLEClientConnected = false; @@ -321,3 +323,12 @@ void loopBLE() { bluetoothRebootCheck(); } + +#else + +/// Given a level between 0-100, update the BLE attribute +void updateBatteryLevel(uint8_t level) {} +void deinitBLE() {} +void loopBLE() {} + +#endif diff --git a/src/esp32/BluetoothUtil.h b/src/esp32/BluetoothUtil.h index 67797a0ce..4773cb546 100644 --- a/src/esp32/BluetoothUtil.h +++ b/src/esp32/BluetoothUtil.h @@ -8,8 +8,7 @@ #include #include "SimpleAllocator.h" -// Now handled by BluetoothUtil.cpp -// BLEService *createDeviceInfomationService(BLEServer* server, uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version); +#ifdef CONFIG_BLUEDROID_ENABLED // Help routine to add a description to any BLECharacteristic and add it to the service void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description); @@ -23,11 +22,9 @@ uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue); using StartBluetoothPinScreenCallback = std::function; using StopBluetoothPinScreenCallback = std::function; -void loopBLE(); BLEServer *initBLE( StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); -void deinitBLE(); /// Add a characteristic that we will delete when we restart BLECharacteristic *addBLECharacteristic(BLECharacteristic *c); @@ -35,8 +32,12 @@ BLECharacteristic *addBLECharacteristic(BLECharacteristic *c); /// Add a characteristic that we will delete when we restart BLEDescriptor *addBLEDescriptor(BLEDescriptor *c); -/// Given a level between 0-100, update the BLE attribute -void updateBatteryLevel(uint8_t level); - /// Any bluetooth objects you allocate _must_ come from this pool if you want to be able to call deinitBLE() extern SimpleAllocator btPool; + +#endif + +/// Given a level between 0-100, update the BLE attribute +void updateBatteryLevel(uint8_t level); +void deinitBLE(); +void loopBLE(); \ No newline at end of file diff --git a/src/esp32/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp index 9bc41459a..a087d3be2 100644 --- a/src/esp32/MeshBluetoothService.cpp +++ b/src/esp32/MeshBluetoothService.cpp @@ -1,11 +1,7 @@ -#include "MeshBluetoothService.h" -#include "BluetoothUtil.h" -#include -#include -#include -#include -#include "CallbackCharacteristic.h" +#include +#include + #include "GPS.h" #include "MeshService.h" #include "NodeDB.h" @@ -15,6 +11,14 @@ #include "mesh-pb-constants.h" #include "mesh.pb.h" +#ifdef CONFIG_BLUEDROID_ENABLED + +#include +#include +#include "CallbackCharacteristic.h" +#include "BluetoothUtil.h" +#include "MeshBluetoothService.h" + // 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)]; @@ -141,3 +145,10 @@ void destroyMeshBluetoothService() meshFromNumCharacteristic = NULL; } + +#else + +void destroyMeshBluetoothService() {} +void stopMeshBluetoothService() {} + +#endif \ No newline at end of file diff --git a/src/esp32/MeshBluetoothService.h b/src/esp32/MeshBluetoothService.h index 17916fa91..c0a95a0b6 100644 --- a/src/esp32/MeshBluetoothService.h +++ b/src/esp32/MeshBluetoothService.h @@ -4,12 +4,11 @@ #include #include +#ifdef CONFIG_BLUEDROID_ENABLED + BLEService *createMeshBluetoothService(BLEServer *server); + +#endif + void destroyMeshBluetoothService(); - -/** - * Tell any bluetooth clients that the number of rx packets has changed - */ -void bluetoothNotifyFromNum(uint32_t newValue); - void stopMeshBluetoothService(); \ No newline at end of file diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index 0a0b98cde..666e47b0e 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -17,9 +17,7 @@ void reinitBluetooth() { DEBUG_MSG("Starting bluetooth\n"); - // FIXME - we are leaking like crazy - // AllocatorScope scope(btPool); - +#ifdef CONFIG_BLUEDROID_ENABLED // Note: these callbacks might be coming in from a different thread. BLEServer *serve = initBLE( [](uint32_t pin) { @@ -32,6 +30,7 @@ void reinitBluetooth() // Start advertising - this must be done _after_ creating all services serve->getAdvertising()->start(); +#endif } // Enable/disable bluetooth. From 102085808fd9936b495bd57b9f223e05c31a217f Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 21 Jul 2020 11:46:39 -0700 Subject: [PATCH 04/25] WIP nimble now builds --- docs/software/TODO.md | 27 +++++++++---- platformio.ini | 2 +- src/esp32/BluetoothUtil.cpp | 80 +++++++++++++++++++++++++++++++++++-- src/esp32/BluetoothUtil.h | 10 ++--- src/esp32/main-esp32.cpp | 21 ---------- 5 files changed, 103 insertions(+), 37 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b10935b9c..3ea06f954 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,13 +2,26 @@ You probably don't care about this section - skip to the next one. -- Nimble getting started https://espressif-esp-idf.readthedocs-hosted.com/zh_CN/release-v3.3/api-reference/bluetooth/nimble/index.html#overview? could it work with arduino esp-idf 4.2 -- update protocol description per cyclomies -- update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2 -- update faq on recommended android version and phones -- add help link inside the app, reference a page on the wiki -- turn on amazon reviews support -- add a tablet layout (with map next to messages) in the android app +Nimble tasks: + +- Nimble getting started https://espressif-esp-idf.readthedocs-hosted.com/zh_CN/release-v3.3/api-reference/bluetooth/nimble/index.html#overview? could it work with arduino esp-idf 4.2 +- implement nimble device api +- setup advertising https://mynewt.apache.org/latest/tutorials/ble/bleprph/bleprph-sections/bleprph-gap-event.html +- add security +- test with app +- restart advertising after client disconnects +- make sleep work +- check BLE handle stability +- apply nimble RPA patches +- start RPA long test +- implement nimble software update api + +* update protocol description per cyclomies email thread +* update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2 +* update faq on recommended android version and phones +* add help link inside the app, reference a page on the wiki +* turn on amazon reviews support +* add a tablet layout (with map next to messages) in the android app # Medium priority diff --git a/platformio.ini b/platformio.ini index d3a38bfb5..c1f0152e3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ src_filter = upload_speed = 921600 debug_init_break = tbreak setup build_flags = - ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue + ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt diff --git a/src/esp32/BluetoothUtil.cpp b/src/esp32/BluetoothUtil.cpp index cc2e34225..50c36b347 100644 --- a/src/esp32/BluetoothUtil.cpp +++ b/src/esp32/BluetoothUtil.cpp @@ -324,11 +324,85 @@ void loopBLE() bluetoothRebootCheck(); } +// This routine is called multiple times, once each time we come back from sleep +void reinitBluetooth() +{ + DEBUG_MSG("Starting bluetooth\n"); + + // Note: these callbacks might be coming in from a different thread. + BLEServer *serve = initBLE( + [](uint32_t pin) { + powerFSM.trigger(EVENT_BLUETOOTH_PAIR); + screen.startBluetoothPinScreen(pin); + }, + []() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, optstr(APP_VERSION), + optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr + createMeshBluetoothService(serve); + + // Start advertising - this must be done _after_ creating all services + serve->getAdvertising()->start(); +} + #else +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +// Force arduino to keep ble data around +bool btInUse() +{ + return false; +} + /// Given a level between 0-100, update the BLE attribute -void updateBatteryLevel(uint8_t level) {} -void deinitBLE() {} -void loopBLE() {} +void updateBatteryLevel(uint8_t level) +{ + // FIXME +} + +void deinitBLE() +{ + // FIXME - do we need to dealloc things? - what needs to stay alive across light sleep? + auto ret = nimble_port_stop(); + assert(ret == ESP_OK); + + nimble_port_deinit(); // teardown nimble datastructures + nimble_port_freertos_deinit(); // delete the task + + ret = esp_nimble_hci_and_controller_deinit(); + assert(ret == ESP_OK); +} + +void loopBLE() +{ + // FIXME +} + +static void ble_host_task(void *param) +{ + nimble_port_run(); // This function will return only when nimble_port_stop() is executed. + // nimble_port_freertos_deinit(); +} + +// This routine is called multiple times, once each time we come back from sleep +void reinitBluetooth() +{ + DEBUG_MSG("Starting bluetooth\n"); + + // FIXME - if waking from light sleep, only esp_nimble_hci_init + // FIXME - why didn't this version work? + // auto res = esp_nimble_hci_and_controller_init(); + auto res = esp_nimble_hci_init(); + DEBUG_MSG("BLE result %d\n", res); + assert(res == ESP_OK); + + nimble_port_init(); + + // FIXME Initialize the required NimBLE host configuration parameters and callbacks + // Perform application specific tasks / initialization + + nimble_port_freertos_init(ble_host_task); +} #endif diff --git a/src/esp32/BluetoothUtil.h b/src/esp32/BluetoothUtil.h index 4773cb546..36ba4d21d 100644 --- a/src/esp32/BluetoothUtil.h +++ b/src/esp32/BluetoothUtil.h @@ -2,11 +2,11 @@ #include +#include "SimpleAllocator.h" #include #include #include #include -#include "SimpleAllocator.h" #ifdef CONFIG_BLUEDROID_ENABLED @@ -22,9 +22,8 @@ uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue); using StartBluetoothPinScreenCallback = std::function; using StopBluetoothPinScreenCallback = std::function; -BLEServer *initBLE( - StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, - std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); +BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, + std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); /// Add a characteristic that we will delete when we restart BLECharacteristic *addBLECharacteristic(BLECharacteristic *c); @@ -40,4 +39,5 @@ extern SimpleAllocator btPool; /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); void deinitBLE(); -void loopBLE(); \ No newline at end of file +void loopBLE(); +void reinitBluetooth(); \ No newline at end of file diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index 666e47b0e..1a96eed41 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -12,27 +12,6 @@ bool bluetoothOn; -// This routine is called multiple times, once each time we come back from sleep -void reinitBluetooth() -{ - DEBUG_MSG("Starting bluetooth\n"); - -#ifdef CONFIG_BLUEDROID_ENABLED - // Note: these callbacks might be coming in from a different thread. - BLEServer *serve = initBLE( - [](uint32_t pin) { - powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen.startBluetoothPinScreen(pin); - }, - []() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, optstr(APP_VERSION), - optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr - createMeshBluetoothService(serve); - - // Start advertising - this must be done _after_ creating all services - serve->getAdvertising()->start(); -#endif -} - // Enable/disable bluetooth. void setBluetoothEnable(bool on) { From 7f6dc104f004d4da6ada49f3a485edadd62bdb5a Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 09:51:57 -0700 Subject: [PATCH 05/25] nimble WIP - add advertising boilerplate --- docs/software/TODO.md | 3 +- platformio.ini | 2 +- src/BluetoothCommon.cpp | 12 ++ src/BluetoothCommon.h | 4 + src/esp32/BluetoothUtil.cpp | 351 +++++++++++++++++++++++++++++++++-- src/nimble/NimbleDefs.c | 44 +++++ src/nimble/NimbleDefs.h | 23 +++ src/nrf52/NRF52Bluetooth.cpp | 11 +- 8 files changed, 425 insertions(+), 25 deletions(-) create mode 100644 src/BluetoothCommon.cpp create mode 100644 src/nimble/NimbleDefs.c create mode 100644 src/nimble/NimbleDefs.h diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 3ea06f954..7cac0626e 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -7,8 +7,9 @@ Nimble tasks: - Nimble getting started https://espressif-esp-idf.readthedocs-hosted.com/zh_CN/release-v3.3/api-reference/bluetooth/nimble/index.html#overview? could it work with arduino esp-idf 4.2 - implement nimble device api - setup advertising https://mynewt.apache.org/latest/tutorials/ble/bleprph/bleprph-sections/bleprph-gap-event.html -- add security +- add security (at least bonding) - test with app +- remove unsecured read/write access - restart advertising after client disconnects - make sleep work - check BLE handle stability diff --git a/platformio.ini b/platformio.ini index c1f0152e3..fe3aed87c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ src_filter = upload_speed = 921600 debug_init_break = tbreak setup build_flags = - ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble + ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11 # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp new file mode 100644 index 000000000..a12a52cf9 --- /dev/null +++ b/src/BluetoothCommon.cpp @@ -0,0 +1,12 @@ +#include "BluetoothCommon.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 +const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, + 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b}; +const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1, + 0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7}; +const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, + 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b}; +const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, + 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 61a8fe5ea..26c7b2cef 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -12,5 +12,9 @@ #define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" +// NRF52 wants these constants as byte arrays +// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER +extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[]; + /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); \ No newline at end of file diff --git a/src/esp32/BluetoothUtil.cpp b/src/esp32/BluetoothUtil.cpp index 50c36b347..ab37ceefb 100644 --- a/src/esp32/BluetoothUtil.cpp +++ b/src/esp32/BluetoothUtil.cpp @@ -345,9 +345,37 @@ void reinitBluetooth() #else -#include "esp_nimble_hci.h" -#include "nimble/nimble_port.h" -#include "nimble/nimble_port_freertos.h" +#include "host/util/util.h" +#include "nimble/NimbleDefs.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +static uint8_t own_addr_type; + +int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + return BLE_ATT_ERR_UNLIKELY; // unimplemented +} + +int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + return BLE_ATT_ERR_UNLIKELY; // unimplemented +} + +int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + return BLE_ATT_ERR_UNLIKELY; // unimplemented +} + +// A C++ version of BLE_UUID128_INIT +#define BLE_UUID128_INIT_CPP(uuid128...) \ + { \ + u : { \ + type: \ + BLE_UUID_TYPE_128 \ + } \ + , value: { uuid128 } \ + } // Force arduino to keep ble data around bool btInUse() @@ -366,12 +394,6 @@ void deinitBLE() // FIXME - do we need to dealloc things? - what needs to stay alive across light sleep? auto ret = nimble_port_stop(); assert(ret == ESP_OK); - - nimble_port_deinit(); // teardown nimble datastructures - nimble_port_freertos_deinit(); // delete the task - - ret = esp_nimble_hci_and_controller_deinit(); - assert(ret == ESP_OK); } void loopBLE() @@ -379,10 +401,275 @@ void loopBLE() // FIXME } +extern "C" void ble_store_config_init(void); + +/// Print a macaddr +static void print_addr(const uint8_t *v) {} + +/** + * Logs information about a connection to the console. + */ +static void print_conn_desc(struct ble_gap_conn_desc *desc) +{ + DEBUG_MSG("handle=%d our_ota_addr_type=%d our_ota_addr=", desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + DEBUG_MSG(" our_id_addr_type=%d our_id_addr=", desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + DEBUG_MSG(" peer_ota_addr_type=%d peer_ota_addr=", desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + DEBUG_MSG(" peer_id_addr_type=%d peer_id_addr=", desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + DEBUG_MSG(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, desc->supervision_timeout, desc->sec_state.encrypted, + desc->sec_state.authenticated, desc->sec_state.bonded); +} + +static void advertise(); + +/** + * The nimble host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that forms. + * bleprph uses the same callback for all connections. + * + * @param event The type of event being signalled. + * @param ctxt Various information pertaining to the event. + * @param arg Application-specified argument; unused by + * bleprph. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int bleprph_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + DEBUG_MSG("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status); + if (event->connect.status == 0) { + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + } + DEBUG_MSG("\n"); + + if (event->connect.status != 0) { + /* Connection failed; resume advertising. */ + advertise(); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + DEBUG_MSG("disconnect; reason=%d ", event->disconnect.reason); + // bleprph_print_conn_desc(&event->disconnect.conn); + DEBUG_MSG("\n"); + + /* Connection terminated; resume advertising. */ + advertise(); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + /* The central has updated the connection parameters. */ + DEBUG_MSG("connection updated; status=%d ", event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + // bleprph_print_conn_desc(&desc); + DEBUG_MSG("\n"); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + DEBUG_MSG("advertise complete; reason=%d", event->adv_complete.reason); + advertise(); + return 0; + + case BLE_GAP_EVENT_ENC_CHANGE: + /* Encryption has been enabled or disabled for this connection. */ + DEBUG_MSG("encryption change event; status=%d ", event->enc_change.status); + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + assert(rc == 0); + // bleprph_print_conn_desc(&desc); + DEBUG_MSG("\n"); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + DEBUG_MSG("subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, event->subscribe.attr_handle, event->subscribe.reason, + event->subscribe.prev_notify, event->subscribe.cur_notify, event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + return 0; + + case BLE_GAP_EVENT_MTU: + DEBUG_MSG("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + /* We already have a bond with the peer, but it is attempting to + * establish a new secure link. This app sacrifices security for + * convenience: just throw away the old bond and accept the new link. + */ + + /* Delete the old bond. */ + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + ble_store_util_delete_peer(&desc.peer_id_addr); + + /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should + * continue with the pairing operation. + */ + return BLE_GAP_REPEAT_PAIRING_RETRY; + + case BLE_GAP_EVENT_PASSKEY_ACTION: + DEBUG_MSG("PASSKEY_ACTION_EVENT started \n"); + struct ble_sm_io pkey = {0}; + + if (event->passkey.params.action == BLE_SM_IOACT_DISP) { + pkey.action = event->passkey.params.action; + pkey.passkey = 123456; // This is the passkey to be entered on peer + DEBUG_MSG("Enter passkey %d on the peer side", pkey.passkey); + rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); + DEBUG_MSG("ble_sm_inject_io result: %d\n", rc); + } else { + DEBUG_MSG("FIXME - unexpected auth type\n"); + } + return 0; + } + + return 0; +} +/** + * Enables advertising with the following parameters: + * o General discoverable mode. + * o Undirected connectable mode. + */ +static void advertise(void) +{ + struct ble_gap_adv_params adv_params; + struct ble_hs_adv_fields fields; + const char *name; + int rc; + + /** + * Set the advertisement data included in our advertisements: + * o Flags (indicates advertisement type and other general info). + * o Advertising tx power. + * o Device name. + * o 16-bit service UUIDs (alert notifications). + */ + + memset(&fields, 0, sizeof fields); + + /* Advertise two flags: + * o Discoverability in forthcoming advertisement (general) + * o BLE-only (BR/EDR unsupported). + */ + fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; + + /* Indicate that the TX power level field should be included; have the + * stack fill this value automatically. This is done by assigning the + * special value BLE_HS_ADV_TX_PWR_LVL_AUTO. + */ + fields.tx_pwr_lvl_is_present = 1; + fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + + name = ble_svc_gap_device_name(); + fields.name = (uint8_t *)name; + fields.name_len = strlen(name); + fields.name_is_complete = 1; + + // fields.uuids16 = (ble_uuid16_t[]){BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)}; + // fields.num_uuids16 = 1; + // fields.uuids16_is_complete = 1; + + rc = ble_gap_adv_set_fields(&fields); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc); + return; + } + + /* Begin advertising. */ + memset(&adv_params, 0, sizeof adv_params); + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + // FIXME - use RPA for first parameter + rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, bleprph_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc); + return; + } +} + +static void bleprph_on_reset(int reason) +{ + DEBUG_MSG("Resetting state; reason=%d\n", reason); +} + +static void bleprph_on_sync(void) +{ + int rc; + + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + DEBUG_MSG("error determining address type; rc=%d\n", rc); + return; + } + + /* Printing ADDR */ + uint8_t addr_val[6] = {0}; + rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL); + + DEBUG_MSG("Device Address: "); + print_addr(addr_val); + DEBUG_MSG("\n"); + /* Begin advertising. */ + advertise(); +} + static void ble_host_task(void *param) { + DEBUG_MSG("BLE task running\n"); nimble_port_run(); // This function will return only when nimble_port_stop() is executed. - // nimble_port_freertos_deinit(); + + nimble_port_deinit(); // teardown nimble datastructures + nimble_port_freertos_deinit(); // delete the task + + auto ret = esp_nimble_hci_and_controller_deinit(); + assert(ret == ESP_OK); +} + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + DEBUG_MSG("registered service %s with handle=%d\n", ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + DEBUG_MSG("registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), ctxt->chr.def_handle, ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + DEBUG_MSG("registering descriptor %s with handle=%d\n", ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } } // This routine is called multiple times, once each time we come back from sleep @@ -394,13 +681,51 @@ void reinitBluetooth() // FIXME - why didn't this version work? // auto res = esp_nimble_hci_and_controller_init(); auto res = esp_nimble_hci_init(); - DEBUG_MSG("BLE result %d\n", res); + // DEBUG_MSG("BLE result %d\n", res); assert(res == ESP_OK); nimble_port_init(); - // FIXME Initialize the required NimBLE host configuration parameters and callbacks - // Perform application specific tasks / initialization + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = bleprph_on_reset; + ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY; +#ifdef CONFIG_EXAMPLE_BONDING + ble_hs_cfg.sm_bonding = 1; +#endif +#ifdef CONFIG_EXAMPLE_MITM + ble_hs_cfg.sm_mitm = 1; +#endif +#ifdef CONFIG_EXAMPLE_USE_SC + ble_hs_cfg.sm_sc = 1; +#else + ble_hs_cfg.sm_sc = 0; +#ifdef CONFIG_EXAMPLE_BONDING + ble_hs_cfg.sm_our_key_dist = 1; + ble_hs_cfg.sm_their_key_dist = 1; +#endif +#endif + + // add standard GAP services + ble_svc_gap_init(); + ble_svc_gatt_init(); + + res = ble_gatts_count_cfg( + gatt_svr_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_svr_svcs); + assert(res == 0); + + /* Set the default device name. */ + res = ble_svc_gap_device_name_set("nimble-bleprph"); + assert(res == 0); + + /* XXX Need to have template for store */ + ble_store_config_init(); nimble_port_freertos_init(ble_host_task); } diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c new file mode 100644 index 000000000..1ce7d8e58 --- /dev/null +++ b/src/nimble/NimbleDefs.c @@ -0,0 +1,44 @@ +#include "NimbleDefs.h" + +// A C++ version of BLE_UUID128_INIT +#define BLE_UUID128_INIT_CPP(uuid128...) \ + { \ + u : { \ + type: \ + BLE_UUID_TYPE_128 \ + } \ + , value: { uuid128 } \ + } + +static const ble_uuid128_t mesh_service_uuid = + BLE_UUID128_INIT(0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b); + +static const ble_uuid128_t toradio_uuid = + BLE_UUID128_INIT(0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1, 0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7); + +static const ble_uuid128_t fromradio_uuid = + BLE_UUID128_INIT(0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b); + +static const ble_uuid128_t fromnum_uuid = + BLE_UUID128_INIT(0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed); + +const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service: Security test. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &mesh_service_uuid.u, + .characteristics = (struct ble_gatt_chr_def[]){{ + /*** Characteristic: Random number generator. */ + .uuid = &toradio_uuid.u, + .access_cb = toradio_callback, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + }, + { + 0, /* No more characteristics in this service. */ + }}, + }, + + { + 0, /* No more services. */ + }, +}; diff --git a/src/nimble/NimbleDefs.h b/src/nimble/NimbleDefs.h new file mode 100644 index 000000000..e74392c72 --- /dev/null +++ b/src/nimble/NimbleDefs.h @@ -0,0 +1,23 @@ +#pragma once + +#include "esp_nimble_hci.h" +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); + +int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); + +int fromnum_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_svr_svcs[]; + +#ifdef __cplusplus +}; +#endif \ No newline at end of file diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 2ae864aae..9309e645e 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -4,16 +4,7 @@ #include "main.h" #include -// NRF52 wants these constants as byte arrays -// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER -const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, - 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b}; -const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1, - 0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7}; -const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, - 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b}; -const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, - 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; + static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); From d674aaaa29f519a8385ec788d07a181b15d94d0f Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 10:23:56 -0700 Subject: [PATCH 06/25] sometimes save config fails on ublox, don't cause a reboot for that --- src/error.h | 2 +- src/gps/UBloxGPS.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/error.h b/src/error.h index 6adcc0ecb..6a2bae249 100644 --- a/src/error.h +++ b/src/error.h @@ -3,7 +3,7 @@ #include /// Error codes for critical error -enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait, ErrNoRadio, ErrUnspecified }; +enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait, ErrNoRadio, ErrUnspecified, UBloxInitFailed }; /// Record an error that should be reported via analytics void recordCriticalError(CriticalErrorCode code, uint32_t address = 0); diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index b63241c38..0ed506f64 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -1,4 +1,5 @@ #include "UBloxGPS.h" +#include "error.h" #include "sleep.h" #include @@ -83,7 +84,8 @@ bool UBloxGPS::setup() assert(ok); } ok = ublox.saveConfiguration(3000); - assert(ok); + if (!ok) + recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device @@ -150,7 +152,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s // bogus lat lon is reported as 0 or 0 (can be bogus just for one) // Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg! - hasValidLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0); + hasValidLocation = + (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0); // we only notify if position has changed due to a new fix if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only From 531f488fe8033f90518dd50133d8dc43e8e09881 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 10:46:01 -0700 Subject: [PATCH 07/25] WIP nimble ugly but advertise works --- platformio.ini | 1 + src/esp32/BluetoothUtil.cpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index fe3aed87c..600c30b25 100644 --- a/platformio.ini +++ b/platformio.ini @@ -79,6 +79,7 @@ upload_speed = 921600 debug_init_break = tbreak setup build_flags = ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11 + -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt diff --git a/src/esp32/BluetoothUtil.cpp b/src/esp32/BluetoothUtil.cpp index ab37ceefb..1921b8f7e 100644 --- a/src/esp32/BluetoothUtil.cpp +++ b/src/esp32/BluetoothUtil.cpp @@ -378,9 +378,9 @@ int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt } // Force arduino to keep ble data around -bool btInUse() +extern "C" bool btInUse() { - return false; + return true; } /// Given a level between 0-100, update the BLE attribute @@ -605,12 +605,13 @@ static void advertise(void) } } -static void bleprph_on_reset(int reason) +static void on_reset(int reason) { + // 19 == BLE_HS_ETIMEOUT_HCI DEBUG_MSG("Resetting state; reason=%d\n", reason); } -static void bleprph_on_sync(void) +static void on_sync(void) { int rc; @@ -676,19 +677,20 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) void reinitBluetooth() { DEBUG_MSG("Starting bluetooth\n"); + esp_log_level_set("BTDM_INIT", ESP_LOG_VERBOSE); // FIXME - if waking from light sleep, only esp_nimble_hci_init // FIXME - why didn't this version work? - // auto res = esp_nimble_hci_and_controller_init(); - auto res = esp_nimble_hci_init(); + auto res = esp_nimble_hci_and_controller_init(); + // auto res = esp_nimble_hci_init(); // DEBUG_MSG("BLE result %d\n", res); assert(res == ESP_OK); nimble_port_init(); /* Initialize the NimBLE host configuration. */ - ble_hs_cfg.reset_cb = bleprph_on_reset; - ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.reset_cb = on_reset; + ble_hs_cfg.sync_cb = on_sync; ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; ble_hs_cfg.store_status_cb = ble_store_util_status_rr; From b6a3deb341b72cea18897a7759f46973e9a90491 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 12:08:54 -0700 Subject: [PATCH 08/25] nimble WIP - writes kinda work now --- docs/software/TODO.md | 1 + src/esp32/BluetoothSoftwareUpdate.cpp | 12 +++-- src/esp32/main-esp32.cpp | 2 +- src/main.cpp | 2 +- src/{esp32 => nimble}/BluetoothUtil.cpp | 71 ++++++++++++++++++++----- src/{esp32 => nimble}/BluetoothUtil.h | 0 src/nimble/NimbleDefs.c | 29 ++++++---- src/sleep.cpp | 18 +++---- 8 files changed, 96 insertions(+), 39 deletions(-) rename src/{esp32 => nimble}/BluetoothUtil.cpp (92%) rename src/{esp32 => nimble}/BluetoothUtil.h (100%) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 7cac0626e..2d53048b7 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -15,6 +15,7 @@ Nimble tasks: - check BLE handle stability - apply nimble RPA patches - start RPA long test +- use a random pairing key rather than 123456 - implement nimble software update api * update protocol description per cyclomies email thread diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index a1143e964..7477ded05 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -1,17 +1,19 @@ +#include + +#ifdef CONFIG_BLUEDROID_ENABLED + +#include "../concurrency/LockGuard.h" +#include "../timing.h" #include "BluetoothSoftwareUpdate.h" #include "BluetoothUtil.h" #include "RadioLibInterface.h" #include "configuration.h" -#include "../concurrency/LockGuard.h" -#include "../timing.h" -#include + #include #include #include #include -#ifdef CONFIG_BLUEDROID_ENABLED - #include "CallbackCharacteristic.h" CRC32 crc; diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index 1a96eed41..5936e8c8e 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -1,9 +1,9 @@ -#include "BluetoothUtil.h" #include "MeshBluetoothService.h" #include "PowerFSM.h" #include "configuration.h" #include "esp_task_wdt.h" #include "main.h" +#include "nimble/BluetoothUtil.h" #include "sleep.h" #include "target_specific.h" #include "utils.h" diff --git a/src/main.cpp b/src/main.cpp index 92c8f424d..dfbe7288d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,8 +43,8 @@ // #include #ifndef NO_ESP32 -#include "BluetoothUtil.h" #include "WiFi.h" +#include "nimble/BluetoothUtil.h" #endif #include "RF95Interface.h" diff --git a/src/esp32/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp similarity index 92% rename from src/esp32/BluetoothUtil.cpp rename to src/nimble/BluetoothUtil.cpp index 1921b8f7e..f856e27bc 100644 --- a/src/esp32/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -345,37 +345,75 @@ void reinitBluetooth() #else +#include "PhoneAPI.h" #include "host/util/util.h" +#include "main.h" #include "nimble/NimbleDefs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" static uint8_t own_addr_type; +// 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(FromRadio_size, ToRadio_size)]; + +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"); + // fromNum.notify32(fromRadioNum); + } +}; + +static BluetoothPhoneAPI *bluetoothPhoneAPI; + int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - return BLE_ATT_ERR_UNLIKELY; // unimplemented + auto om = ctxt->om; + uint16_t len = 0; + + auto rc = ble_hs_mbuf_to_flat(om, trBytes, sizeof(trBytes), &len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len); + + bluetoothPhoneAPI->handleToRadio(trBytes, len); + return 0; } int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - return BLE_ATT_ERR_UNLIKELY; // unimplemented + DEBUG_MSG("BLE fromRadio called\n"); + size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); + + // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue + // or make empty if the queue is empty + auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes); + assert(rc == 0); + + return 0; // success } int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - return BLE_ATT_ERR_UNLIKELY; // unimplemented -} + static uint32_t fromNum = 0; -// A C++ version of BLE_UUID128_INIT -#define BLE_UUID128_INIT_CPP(uuid128...) \ - { \ - u : { \ - type: \ - BLE_UUID_TYPE_128 \ - } \ - , value: { uuid128 } \ - } + DEBUG_MSG("BLE fromNum called\n"); + auto rc = os_mbuf_append(ctxt->om, &fromNum, + sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness + assert(rc == 0); + + return 0; // success +} // Force arduino to keep ble data around extern "C" bool btInUse() @@ -679,6 +717,11 @@ void reinitBluetooth() DEBUG_MSG("Starting bluetooth\n"); esp_log_level_set("BTDM_INIT", ESP_LOG_VERBOSE); + if (!bluetoothPhoneAPI) { + bluetoothPhoneAPI = new BluetoothPhoneAPI(); + bluetoothPhoneAPI->init(); + } + // FIXME - if waking from light sleep, only esp_nimble_hci_init // FIXME - why didn't this version work? auto res = esp_nimble_hci_and_controller_init(); @@ -723,7 +766,7 @@ void reinitBluetooth() assert(res == 0); /* Set the default device name. */ - res = ble_svc_gap_device_name_set("nimble-bleprph"); + res = ble_svc_gap_device_name_set(getDeviceName()); assert(res == 0); /* XXX Need to have template for store */ diff --git a/src/esp32/BluetoothUtil.h b/src/nimble/BluetoothUtil.h similarity index 100% rename from src/esp32/BluetoothUtil.h rename to src/nimble/BluetoothUtil.h diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c index 1ce7d8e58..1e1f09a85 100644 --- a/src/nimble/NimbleDefs.c +++ b/src/nimble/NimbleDefs.c @@ -27,15 +27,26 @@ const struct ble_gatt_svc_def gatt_svr_svcs[] = { /*** Service: Security test. */ .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &mesh_service_uuid.u, - .characteristics = (struct ble_gatt_chr_def[]){{ - /*** Characteristic: Random number generator. */ - .uuid = &toradio_uuid.u, - .access_cb = toradio_callback, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, - }, - { - 0, /* No more characteristics in this service. */ - }}, + .characteristics = + (struct ble_gatt_chr_def[]){{ + // FIXME - remove non ENC access + .uuid = &toradio_uuid.u, + .access_cb = toradio_callback, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC, + }, + { + .uuid = &fromradio_uuid.u, + .access_cb = fromradio_callback, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + }, + { + .uuid = &fromnum_uuid.u, + .access_cb = fromnum_callback, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, + { + 0, /* No more characteristics in this service. */ + }}, }, { diff --git a/src/sleep.cpp b/src/sleep.cpp index 59106494c..f7d61eb77 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -5,9 +5,9 @@ #include "NodeDB.h" #include "configuration.h" #include "error.h" -#include "timing.h" #include "main.h" #include "target_specific.h" +#include "timing.h" #ifndef NO_ESP32 #include "esp32/pm.h" @@ -16,7 +16,7 @@ #include #include -#include "BluetoothUtil.h" +#include "nimble/BluetoothUtil.h" esp_sleep_source_t wakeCause; // the reason we booted this time #endif @@ -294,18 +294,18 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r /** * enable modem sleep mode as needed and available. Should lower our CPU current draw to an average of about 20mA. - * + * * per https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/power_management.html - * + * * supposedly according to https://github.com/espressif/arduino-esp32/issues/475 this is already done in arduino */ void enableModemSleep() { - static esp_pm_config_esp32_t config; // filled with zeros because bss + static esp_pm_config_esp32_t config; // filled with zeros because bss - config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - config.min_freq_mhz = 20; // 10Mhz is minimum recommended - config.light_sleep_enable = false; - DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config)); + config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; + config.min_freq_mhz = 20; // 10Mhz is minimum recommended + config.light_sleep_enable = false; + DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config)); } #endif From 00cf3a768e270adcea38752445ca943bf64217bf Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 13:50:30 -0700 Subject: [PATCH 09/25] nimble WIP turn on bonding and security --- src/nimble/BluetoothUtil.cpp | 10 ---------- src/nimble/NimbleDefs.c | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index f856e27bc..3a5239c94 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -738,21 +738,11 @@ void reinitBluetooth() ble_hs_cfg.store_status_cb = ble_store_util_status_rr; ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY; -#ifdef CONFIG_EXAMPLE_BONDING ble_hs_cfg.sm_bonding = 1; -#endif -#ifdef CONFIG_EXAMPLE_MITM ble_hs_cfg.sm_mitm = 1; -#endif -#ifdef CONFIG_EXAMPLE_USE_SC ble_hs_cfg.sm_sc = 1; -#else - ble_hs_cfg.sm_sc = 0; -#ifdef CONFIG_EXAMPLE_BONDING ble_hs_cfg.sm_our_key_dist = 1; ble_hs_cfg.sm_their_key_dist = 1; -#endif -#endif // add standard GAP services ble_svc_gap_init(); diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c index 1e1f09a85..5be014d5b 100644 --- a/src/nimble/NimbleDefs.c +++ b/src/nimble/NimbleDefs.c @@ -32,17 +32,17 @@ const struct ble_gatt_svc_def gatt_svr_svcs[] = { // FIXME - remove non ENC access .uuid = &toradio_uuid.u, .access_cb = toradio_callback, - .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN, }, { .uuid = &fromradio_uuid.u, .access_cb = fromradio_callback, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN, }, { .uuid = &fromnum_uuid.u, .access_cb = fromnum_callback, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY, }, { 0, /* No more characteristics in this service. */ From c5df1bc885c2b85f8231ec82bce11ec5531031bb Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 15:44:45 -0700 Subject: [PATCH 10/25] Nimble WIP - woot! basic device API works now --- docs/software/TODO.md | 8 ++--- src/nimble/BluetoothUtil.cpp | 57 ++++++++++++++++++++++-------------- src/nimble/NimbleDefs.c | 2 +- src/nimble/NimbleDefs.h | 2 ++ 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 2d53048b7..995576e0d 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,13 +4,9 @@ You probably don't care about this section - skip to the next one. Nimble tasks: -- Nimble getting started https://espressif-esp-idf.readthedocs-hosted.com/zh_CN/release-v3.3/api-reference/bluetooth/nimble/index.html#overview? could it work with arduino esp-idf 4.2 -- implement nimble device api -- setup advertising https://mynewt.apache.org/latest/tutorials/ble/bleprph/bleprph-sections/bleprph-gap-event.html -- add security (at least bonding) +- make notify work - test with app -- remove unsecured read/write access -- restart advertising after client disconnects +- restart advertising after client disconnects (confirm this works if client goes out of range) - make sleep work - check BLE handle stability - apply nimble RPA patches diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 3a5239c94..2538a6146 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -441,8 +441,15 @@ void loopBLE() extern "C" void ble_store_config_init(void); -/// Print a macaddr -static void print_addr(const uint8_t *v) {} +/// Print a macaddr - bytes are stored in reverse order +static void print_addr(const uint8_t v[]) +{ + const int macaddrlen = 6; + + for (int i = 0; i < macaddrlen; i++) { + DEBUG_MSG("%02x%c", v[macaddrlen - i], (i == macaddrlen - 1) ? '\n' : ':'); + } +} /** * Logs information about a connection to the console. @@ -588,11 +595,6 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) */ static void advertise(void) { - struct ble_gap_adv_params adv_params; - struct ble_hs_adv_fields fields; - const char *name; - int rc; - /** * Set the advertisement data included in our advertisements: * o Flags (indicates advertisement type and other general info). @@ -601,44 +603,55 @@ static void advertise(void) * o 16-bit service UUIDs (alert notifications). */ - memset(&fields, 0, sizeof fields); + struct ble_hs_adv_fields adv_fields; + memset(&adv_fields, 0, sizeof adv_fields); /* Advertise two flags: * o Discoverability in forthcoming advertisement (general) * o BLE-only (BR/EDR unsupported). */ - fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; /* Indicate that the TX power level field should be included; have the * stack fill this value automatically. This is done by assigning the * special value BLE_HS_ADV_TX_PWR_LVL_AUTO. */ - fields.tx_pwr_lvl_is_present = 1; - fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; - name = ble_svc_gap_device_name(); - fields.name = (uint8_t *)name; - fields.name_len = strlen(name); - fields.name_is_complete = 1; + const char *name = ble_svc_gap_device_name(); + adv_fields.name = (uint8_t *)name; + adv_fields.name_len = strlen(name); + adv_fields.name_is_complete = 1; - // fields.uuids16 = (ble_uuid16_t[]){BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)}; - // fields.num_uuids16 = 1; - // fields.uuids16_is_complete = 1; - - rc = ble_gap_adv_set_fields(&fields); + auto rc = ble_gap_adv_set_fields(&adv_fields); if (rc != 0) { - MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc); + DEBUG_MSG("error setting advertisement data; rc=%d\n", rc); + return; + } + + // add scan response fields + struct ble_hs_adv_fields scan_fields; + memset(&scan_fields, 0, sizeof scan_fields); + scan_fields.uuids128 = const_cast(&mesh_service_uuid); + scan_fields.num_uuids128 = 1; + scan_fields.uuids128_is_complete = 1; + + rc = ble_gap_adv_rsp_set_fields(&scan_fields); + if (rc != 0) { + DEBUG_MSG("error setting scan response data; rc=%d\n", rc); return; } /* Begin advertising. */ + struct ble_gap_adv_params adv_params; memset(&adv_params, 0, sizeof adv_params); adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // FIXME - use RPA for first parameter rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, bleprph_gap_event, NULL); if (rc != 0) { - MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc); + DEBUG_MSG("error enabling advertisement; rc=%d\n", rc); return; } } diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c index 5be014d5b..b4238d814 100644 --- a/src/nimble/NimbleDefs.c +++ b/src/nimble/NimbleDefs.c @@ -10,7 +10,7 @@ , value: { uuid128 } \ } -static const ble_uuid128_t mesh_service_uuid = +const ble_uuid128_t mesh_service_uuid = BLE_UUID128_INIT(0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b); static const ble_uuid128_t toradio_uuid = diff --git a/src/nimble/NimbleDefs.h b/src/nimble/NimbleDefs.h index e74392c72..7a7d760b4 100644 --- a/src/nimble/NimbleDefs.h +++ b/src/nimble/NimbleDefs.h @@ -18,6 +18,8 @@ int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt extern const struct ble_gatt_svc_def gatt_svr_svcs[]; +extern const ble_uuid128_t mesh_service_uuid; + #ifdef __cplusplus }; #endif \ No newline at end of file From 66b147fb31486e42730468bea3b3d42b0d3a0d5f Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 16:16:28 -0700 Subject: [PATCH 11/25] Nimble WIP fix bluetooth pairing screen --- src/nimble/BluetoothUtil.cpp | 58 +++++++++++++++++------------------- src/nimble/BluetoothUtil.h | 8 ++--- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 2538a6146..e96107f29 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -318,40 +318,31 @@ BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoo return pServer; } -// Called from loop -void loopBLE() -{ - bluetoothRebootCheck(); -} - -// This routine is called multiple times, once each time we come back from sleep -void reinitBluetooth() -{ - DEBUG_MSG("Starting bluetooth\n"); - - // Note: these callbacks might be coming in from a different thread. - BLEServer *serve = initBLE( - [](uint32_t pin) { - powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen.startBluetoothPinScreen(pin); - }, - []() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, optstr(APP_VERSION), - optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr - createMeshBluetoothService(serve); - - // Start advertising - this must be done _after_ creating all services - serve->getAdvertising()->start(); -} +// Note: these callbacks might be coming in from a different thread. +BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION), + optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr #else #include "PhoneAPI.h" +#include "PowerFSM.h" #include "host/util/util.h" #include "main.h" #include "nimble/NimbleDefs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" +static void startCb(uint32_t pin) +{ + powerFSM.trigger(EVENT_BLUETOOTH_PAIR); + screen.startBluetoothPinScreen(pin); +}; + +static void stopCb() +{ + screen.stopBluetoothPinScreen(); +}; + static uint8_t own_addr_type; // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in @@ -511,7 +502,7 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_DISCONNECT: DEBUG_MSG("disconnect; reason=%d ", event->disconnect.reason); - // bleprph_print_conn_desc(&event->disconnect.conn); + print_conn_desc(&event->disconnect.conn); DEBUG_MSG("\n"); /* Connection terminated; resume advertising. */ @@ -523,7 +514,7 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) DEBUG_MSG("connection updated; status=%d ", event->conn_update.status); rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); assert(rc == 0); - // bleprph_print_conn_desc(&desc); + print_conn_desc(&desc); DEBUG_MSG("\n"); return 0; @@ -537,8 +528,11 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) DEBUG_MSG("encryption change event; status=%d ", event->enc_change.status); rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); assert(rc == 0); - // bleprph_print_conn_desc(&desc); + print_conn_desc(&desc); DEBUG_MSG("\n"); + + // Remove our custom PIN request screen. + stopCb(); return 0; case BLE_GAP_EVENT_SUBSCRIBE: @@ -576,12 +570,16 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) if (event->passkey.params.action == BLE_SM_IOACT_DISP) { pkey.action = event->passkey.params.action; - pkey.passkey = 123456; // This is the passkey to be entered on peer - DEBUG_MSG("Enter passkey %d on the peer side", pkey.passkey); + pkey.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", pkey.passkey); + + startCb(pkey.passkey); + rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); DEBUG_MSG("ble_sm_inject_io result: %d\n", rc); } else { - DEBUG_MSG("FIXME - unexpected auth type\n"); + DEBUG_MSG("FIXME - unexpected auth type %d\n", event->passkey.params.action); } return 0; } diff --git a/src/nimble/BluetoothUtil.h b/src/nimble/BluetoothUtil.h index 36ba4d21d..8330afc47 100644 --- a/src/nimble/BluetoothUtil.h +++ b/src/nimble/BluetoothUtil.h @@ -18,10 +18,6 @@ void dumpCharacteristic(BLECharacteristic *c); /** converting endianness pull out a 32 bit value */ uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue); -// TODO(girts): create a class for the bluetooth utils helpers? -using StartBluetoothPinScreenCallback = std::function; -using StopBluetoothPinScreenCallback = std::function; - BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); @@ -36,6 +32,10 @@ extern SimpleAllocator btPool; #endif +// TODO(girts): create a class for the bluetooth utils helpers? +using StartBluetoothPinScreenCallback = std::function; +using StopBluetoothPinScreenCallback = std::function; + /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); void deinitBLE(); From 78ff9a811663ab9f94a6450dc47ce3974efcbd52 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 16:40:00 -0700 Subject: [PATCH 12/25] Nimble WIP - make notify work --- docs/software/TODO.md | 3 +-- src/nimble/BluetoothUtil.cpp | 34 +++++++++++++++++++++++++++++----- src/nimble/NimbleDefs.c | 2 +- src/nimble/NimbleDefs.h | 2 +- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 995576e0d..8bb8f1c80 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,8 +4,7 @@ You probably don't care about this section - skip to the next one. Nimble tasks: -- make notify work -- test with app +- ble bonding is not being kept? - restart advertising after client disconnects (confirm this works if client goes out of range) - make sleep work - check BLE handle stability diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index e96107f29..50ed41c20 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -332,15 +332,21 @@ BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION), #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" +static bool pinShowing; + static void startCb(uint32_t pin) { + pinShowing = true; powerFSM.trigger(EVENT_BLUETOOTH_PAIR); screen.startBluetoothPinScreen(pin); }; static void stopCb() { - screen.stopBluetoothPinScreen(); + if (pinShowing) { + pinShowing = false; + screen.stopBluetoothPinScreen(); + } }; static uint8_t own_addr_type; @@ -349,6 +355,12 @@ static uint8_t own_addr_type; // proccess at once static uint8_t trBytes[max(FromRadio_size, ToRadio_size)]; +static uint16_t fromNumValHandle; +static uint32_t fromNum; + +/// We only allow one BLE connection at a time +static int16_t curConnectionHandle = -1; + class BluetoothPhoneAPI : public PhoneAPI { /** @@ -358,8 +370,14 @@ class BluetoothPhoneAPI : public PhoneAPI { PhoneAPI::onNowHasData(fromRadioNum); - DEBUG_MSG("BLE notify fromNum\n"); - // fromNum.notify32(fromRadioNum); + fromNum = fromRadioNum; + if (curConnectionHandle >= 0 && fromNumValHandle) { + DEBUG_MSG("BLE notify fromNum\n"); + auto res = ble_gattc_notify(curConnectionHandle, fromNumValHandle); + assert(res == 0); + } else { + DEBUG_MSG("No BLE notify\n"); + } } }; @@ -396,8 +414,6 @@ int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - static uint32_t fromNum = 0; - DEBUG_MSG("BLE fromNum called\n"); auto rc = os_mbuf_append(ctxt->om, &fromNum, sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness @@ -491,6 +507,7 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) rc = ble_gap_conn_find(event->connect.conn_handle, &desc); assert(rc == 0); print_conn_desc(&desc); + curConnectionHandle = event->connect.conn_handle; } DEBUG_MSG("\n"); @@ -505,6 +522,8 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) print_conn_desc(&event->disconnect.conn); DEBUG_MSG("\n"); + curConnectionHandle = -1; + /* Connection terminated; resume advertising. */ advertise(); return 0; @@ -710,6 +729,11 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) DEBUG_MSG("registering characteristic %s with " "def_handle=%d val_handle=%d\n", ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), ctxt->chr.def_handle, ctxt->chr.val_handle); + + if (ctxt->chr.chr_def->uuid == &fromnum_uuid.u) { + fromNumValHandle = ctxt->chr.val_handle; + DEBUG_MSG("FromNum handle %d\n", fromNumValHandle); + } break; case BLE_GATT_REGISTER_OP_DSC: diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c index b4238d814..fb9d55188 100644 --- a/src/nimble/NimbleDefs.c +++ b/src/nimble/NimbleDefs.c @@ -19,7 +19,7 @@ static const ble_uuid128_t toradio_uuid = static const ble_uuid128_t fromradio_uuid = BLE_UUID128_INIT(0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b); -static const ble_uuid128_t fromnum_uuid = +const ble_uuid128_t fromnum_uuid = BLE_UUID128_INIT(0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed); const struct ble_gatt_svc_def gatt_svr_svcs[] = { diff --git a/src/nimble/NimbleDefs.h b/src/nimble/NimbleDefs.h index 7a7d760b4..8af85c4cb 100644 --- a/src/nimble/NimbleDefs.h +++ b/src/nimble/NimbleDefs.h @@ -18,7 +18,7 @@ int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt extern const struct ble_gatt_svc_def gatt_svr_svcs[]; -extern const ble_uuid128_t mesh_service_uuid; +extern const ble_uuid128_t mesh_service_uuid, fromnum_uuid; #ifdef __cplusplus }; From 9b4ca95660b8135a5e05710730c3e4e895c0e9ef Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 18:00:56 -0700 Subject: [PATCH 13/25] nimble basically works now. Started long bake for bug #266 --- docs/software/TODO.md | 5 +---- src/nimble/BluetoothUtil.cpp | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 8bb8f1c80..a39b1f009 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,13 +4,10 @@ You probably don't care about this section - skip to the next one. Nimble tasks: -- ble bonding is not being kept? - restart advertising after client disconnects (confirm this works if client goes out of range) - make sleep work - check BLE handle stability -- apply nimble RPA patches -- start RPA long test -- use a random pairing key rather than 123456 +- started RPA long test, jul 22 6pm - implement nimble software update api * update protocol description per cyclomies email thread diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 50ed41c20..71b0aa56a 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -448,13 +448,13 @@ void loopBLE() extern "C" void ble_store_config_init(void); -/// Print a macaddr - bytes are stored in reverse order -static void print_addr(const uint8_t v[]) +/// Print a macaddr - bytes are sometimes stored in reverse order +static void print_addr(const uint8_t v[], bool isReversed = true) { const int macaddrlen = 6; - + for (int i = 0; i < macaddrlen; i++) { - DEBUG_MSG("%02x%c", v[macaddrlen - i], (i == macaddrlen - 1) ? '\n' : ':'); + DEBUG_MSG("%02x%c", v[isReversed ? macaddrlen - i : i], (i == macaddrlen - 1) ? '\n' : ':'); } } @@ -568,6 +568,13 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_REPEAT_PAIRING: + DEBUG_MSG("repeat pairing event; conn_handle=%d " + "cur_key_sz=%d cur_auth=%d cur_sc=%d " + "new_key_sz=%d new_auth=%d new_sc=%d " + "new_bonding=%d\n", + event->repeat_pairing.conn_handle, event->repeat_pairing.cur_key_size, event->repeat_pairing.cur_authenticated, + event->repeat_pairing.cur_sc, event->repeat_pairing.new_key_size, event->repeat_pairing.new_authenticated, + event->repeat_pairing.new_sc, event->repeat_pairing.new_bonding); /* We already have a bond with the peer, but it is attempting to * establish a new secure link. This app sacrifices security for * convenience: just throw away the old bond and accept the new link. @@ -695,9 +702,10 @@ static void on_sync(void) /* Printing ADDR */ uint8_t addr_val[6] = {0}; - rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL); - - DEBUG_MSG("Device Address: "); + int isPrivate = 0; + rc = ble_hs_id_copy_addr(own_addr_type, addr_val, &isPrivate); + assert(rc == 0); + DEBUG_MSG("Addr type %d, Private=%d, Device Address: ", own_addr_type, isPrivate); print_addr(addr_val); DEBUG_MSG("\n"); /* Begin advertising. */ @@ -776,8 +784,9 @@ void reinitBluetooth() ble_hs_cfg.sm_bonding = 1; ble_hs_cfg.sm_mitm = 1; ble_hs_cfg.sm_sc = 1; - ble_hs_cfg.sm_our_key_dist = 1; - ble_hs_cfg.sm_their_key_dist = 1; + // per https://github.com/espressif/esp-idf/issues/5530#issuecomment-652933685 + ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC; + ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC; // add standard GAP services ble_svc_gap_init(); From 014eea2f56b40aa250a07a7565de75a3a90bac58 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 21:26:32 -0700 Subject: [PATCH 14/25] Nimble sleep almost works --- docs/software/TODO.md | 4 + src/mesh/NodeDB.cpp | 10 +- src/nimble/BluetoothUtil.cpp | 314 +++-------------------------------- 3 files changed, 34 insertions(+), 294 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index a39b1f009..e35526a98 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -9,6 +9,8 @@ Nimble tasks: - check BLE handle stability - started RPA long test, jul 22 6pm - implement nimble software update api +- implement nimble battery level service +- implement device info service remaining fields (hw version etc) * update protocol description per cyclomies email thread * update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2 @@ -34,6 +36,8 @@ Items to complete before 1.0. Items after the first final candidate release. +- Turn on RPA addresses for the device side in Nimble +- Try to teardown less of the Nimble protocol stack across sleep - dynamic frequency scaling could save a lot of power on ESP32, but it seems to corrupt uart (even with ref_tick set correctly) - Change back to using a fixed sized MemoryPool rather than MemoryDynamic (see bug #149) - scan to find channels with low background noise? (Use CAD mode of the RF95 to automatically find low noise channels) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index fe816a202..3e44c21d1 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -103,7 +103,7 @@ void NodeDB::resetRadioConfig() crypto->setKey(channelSettings.psk.size, channelSettings.psk.bytes); // temp hack for quicker testing - // devicestate.no_save = true; + devicestate.no_save = true; if (devicestate.no_save) { DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n"); @@ -356,7 +356,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) info->position.time = oldtime; info->has_position = true; updateGUIforNode = info; - notifyObservers(true); //Force an update whether or not our node counts have changed + notifyObservers(true); // Force an update whether or not our node counts have changed break; } @@ -371,7 +371,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) devicestate.has_rx_text_message = true; updateTextMessage = true; powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); - notifyObservers(true); //Force an update whether or not our node counts have changed + notifyObservers(true); // Force an update whether or not our node counts have changed } } break; @@ -390,7 +390,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) if (changed) { updateGUIforNode = info; powerFSM.trigger(EVENT_NODEDB_UPDATED); - notifyObservers(true); //Force an update whether or not our node counts have changed + notifyObservers(true); // Force an update whether or not our node counts have changed // Not really needed - we will save anyways when we go to sleep // We just changed something important about the user, store our DB @@ -400,7 +400,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) } default: { - notifyObservers(); //If the node counts have changed, notify observers + notifyObservers(); // If the node counts have changed, notify observers } } } diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 71b0aa56a..81eb2bfad 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -6,107 +6,7 @@ #include #include -#ifdef CONFIG_BLUEDROID_ENABLED - -SimpleAllocator btPool; - -bool _BLEClientConnected = false; - -class MyServerCallbacks : public BLEServerCallbacks -{ - void onConnect(BLEServer *pServer) { _BLEClientConnected = true; }; - - void onDisconnect(BLEServer *pServer) { _BLEClientConnected = false; } -}; - -#define MAX_DESCRIPTORS 32 -#define MAX_CHARACTERISTICS 32 - -static BLECharacteristic *chars[MAX_CHARACTERISTICS]; -static size_t numChars; -static BLEDescriptor *descs[MAX_DESCRIPTORS]; -static size_t numDescs; - -/// Add a characteristic that we will delete when we restart -BLECharacteristic *addBLECharacteristic(BLECharacteristic *c) -{ - assert(numChars < MAX_CHARACTERISTICS); - chars[numChars++] = c; - return c; -} - -/// Add a characteristic that we will delete when we restart -BLEDescriptor *addBLEDescriptor(BLEDescriptor *c) -{ - assert(numDescs < MAX_DESCRIPTORS); - descs[numDescs++] = c; - - return c; -} - -// Help routine to add a description to any BLECharacteristic and add it to the service -// We default to require an encrypted BOND for all these these characterstics -void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description) -{ - c->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); - - BLEDescriptor *desc = new BLEDescriptor(BLEUUID((uint16_t)ESP_GATT_UUID_CHAR_DESCRIPTION), strlen(description) + 1); - assert(desc); - desc->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); - desc->setValue(description); - c->addDescriptor(desc); - service->addCharacteristic(c); - addBLECharacteristic(c); - addBLEDescriptor(desc); -} - -/** - * Create standard device info service - **/ -BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendor, std::string swVersion, - std::string hwVersion = "") -{ - BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC)); - - BLECharacteristic *swC = - new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ); - BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ); - // BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR), - // BLECharacteristic::PROPERTY_READ); - - /* - * Mandatory characteristic for device info service? - - BLECharacteristic *m_pnpCharacteristic = m_deviceInfoService->createCharacteristic(ESP_GATT_UUID_PNP_ID, - BLECharacteristic::PROPERTY_READ); - - uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version; - uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> - 8), (uint8_t) version }; m_pnpCharacteristic->setValue(pnp, sizeof(pnp)); - */ - swC->setValue(swVersion); - deviceInfoService->addCharacteristic(addBLECharacteristic(swC)); - mfC->setValue(hwVendor); - deviceInfoService->addCharacteristic(addBLECharacteristic(mfC)); - if (!hwVersion.empty()) { - BLECharacteristic *hwvC = - new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ); - hwvC->setValue(hwVersion); - deviceInfoService->addCharacteristic(addBLECharacteristic(hwvC)); - } - // SerialNumberCharacteristic.setValue("FIXME"); - // deviceInfoService->addCharacteristic(&SerialNumberCharacteristic); - - // m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, - // BLECharacteristic::PROPERTY_READ); m_manufacturerCharacteristic->setValue(name); - - /* add these later? - ESP_GATT_UUID_SYSTEM_ID - */ - - // caller must call service->start(); - return deviceInfoService; -} +#if 0 static BLECharacteristic *batteryLevelC; @@ -144,185 +44,13 @@ void updateBatteryLevel(uint8_t level) } } -void dumpCharacteristic(BLECharacteristic *c) -{ - std::string value = c->getValue(); - if (value.length() > 0) { - DEBUG_MSG("New value: "); - for (int i = 0; i < value.length(); i++) - DEBUG_MSG("%c", value[i]); - - DEBUG_MSG("\n"); - } -} - -/** converting endianness pull out a 32 bit value */ -uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue) -{ - std::string value = c->getValue(); - uint32_t r = defaultValue; - - if (value.length() == 4) - r = value[0] | (value[1] << 8UL) | (value[2] << 16UL) | (value[3] << 24UL); - - return r; -} - -class MySecurity : public BLESecurityCallbacks -{ - protected: - bool onConfirmPIN(uint32_t pin) - { - Serial.printf("onConfirmPIN %u\n", pin); - return false; - } - - uint32_t onPassKeyRequest() - { - Serial.println("onPassKeyRequest"); - return 123511; // not used - } - - void onPassKeyNotify(uint32_t pass_key) - { - Serial.printf("onPassKeyNotify %06u\n", pass_key); - startCb(pass_key); - } - - bool onSecurityRequest() - { - Serial.println("onSecurityRequest"); - return true; - } - - void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) - { - if (cmpl.success) { - uint16_t length; - esp_ble_gap_get_whitelist_size(&length); - Serial.printf(" authenticated and connected to phone\n"); - } else { - Serial.printf("phone authenticate failed %d\n", cmpl.fail_reason); - } - - // Remove our custom PIN request screen. - stopCb(); - } - - public: - StartBluetoothPinScreenCallback startCb; - StopBluetoothPinScreenCallback stopCb; -}; - -BLEServer *pServer; - -BLEService *pDevInfo, *pUpdate, *pBattery; - -void deinitBLE() -{ - assert(pServer); - - pServer->getAdvertising()->stop(); - - if (pUpdate != NULL) { - destroyUpdateService(); - - pUpdate->stop(); // we delete them below - pUpdate->executeDelete(); - } - - pBattery->stop(); - pBattery->executeDelete(); - - pDevInfo->stop(); - pDevInfo->executeDelete(); - - // First shutdown bluetooth - BLEDevice::deinit(false); - - // do not delete this - it is dynamically allocated, but only once - statically in BLEDevice - // delete pServer->getAdvertising(); - - if (pUpdate != NULL) - delete pUpdate; - delete pDevInfo; - delete pBattery; - delete pServer; - - batteryLevelC = NULL; // Don't let anyone generate bogus notifies - - for (int i = 0; i < numChars; i++) { - delete chars[i]; - } - numChars = 0; - - for (int i = 0; i < numDescs; i++) - delete descs[i]; - numDescs = 0; - - btPool.reset(); -} - -BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, - std::string deviceName, std::string hwVendor, std::string swVersion, std::string hwVersion) -{ - BLEDevice::init(deviceName); - BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); - - /* - * Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation - */ - static MySecurity mySecurity; - mySecurity.startCb = startBtPinScreen; - mySecurity.stopCb = stopBtPinScreen; - BLEDevice::setSecurityCallbacks(&mySecurity); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - static MyServerCallbacks myCallbacks; - pServer->setCallbacks(&myCallbacks); - - pDevInfo = createDeviceInfomationService(pServer, hwVendor, swVersion, hwVersion); - - pBattery = createBatteryService(pServer); - -#define BLE_SOFTWARE_UPDATE -#ifdef BLE_SOFTWARE_UPDATE - pUpdate = createUpdateService(pServer, hwVendor, swVersion, - hwVersion); // We need to advertise this so our android ble scan operation can see it - - pUpdate->start(); -#endif - - // It seems only one service can be advertised - so for now don't advertise our updater - // pServer->getAdvertising()->addServiceUUID(pUpdate->getUUID()); - - // start all our services (do this after creating all of them) - pDevInfo->start(); - - // FIXME turn on this restriction only after the device is paired with a phone - // advert->setScanFilter(false, true); // We let anyone scan for us (FIXME, perhaps only allow that until we are paired with a - // phone and configured) but only let whitelist phones connect - - static BLESecurity security; // static to avoid allocs - BLESecurity *pSecurity = &security; - pSecurity->setCapability(ESP_IO_CAP_OUT); - - // FIXME - really should be ESP_LE_AUTH_REQ_SC_BOND but it seems there is a bug right now causing that bonding info to be lost - // occasionally? - pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND); - - pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); - - return pServer; -} // Note: these callbacks might be coming in from a different thread. BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION), optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr -#else +#endif #include "PhoneAPI.h" #include "PowerFSM.h" @@ -436,9 +164,23 @@ void updateBatteryLevel(uint8_t level) void deinitBLE() { + DEBUG_MSG("Shutting down bluetooth\n"); + ble_gatts_show_local(); + // FIXME - do we need to dealloc things? - what needs to stay alive across light sleep? auto ret = nimble_port_stop(); assert(ret == ESP_OK); + + nimble_port_deinit(); // teardown nimble datastructures + nimble_port_freertos_deinit(); // delete the task + + ret = esp_nimble_hci_and_controller_deinit(); + assert(ret == ESP_OK); + + ret = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers + assert(ret == ESP_OK); + + DEBUG_MSG("Done shutting down bluetooth\n"); } void loopBLE() @@ -452,7 +194,7 @@ extern "C" void ble_store_config_init(void); static void print_addr(const uint8_t v[], bool isReversed = true) { const int macaddrlen = 6; - + for (int i = 0; i < macaddrlen; i++) { DEBUG_MSG("%02x%c", v[isReversed ? macaddrlen - i : i], (i == macaddrlen - 1) ? '\n' : ':'); } @@ -494,7 +236,7 @@ static void advertise(); * of the return code is specific to the * particular GAP event being signalled. */ -static int bleprph_gap_event(struct ble_gap_event *event, void *arg) +static int gap_event(struct ble_gap_event *event, void *arg) { struct ble_gap_conn_desc desc; int rc; @@ -673,7 +415,7 @@ static void advertise(void) adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // FIXME - use RPA for first parameter - rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, bleprph_gap_event, NULL); + rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, gap_event, NULL); if (rc != 0) { DEBUG_MSG("error enabling advertisement; rc=%d\n", rc); return; @@ -717,11 +459,7 @@ static void ble_host_task(void *param) DEBUG_MSG("BLE task running\n"); nimble_port_run(); // This function will return only when nimble_port_stop() is executed. - nimble_port_deinit(); // teardown nimble datastructures - nimble_port_freertos_deinit(); // delete the task - - auto ret = esp_nimble_hci_and_controller_deinit(); - assert(ret == ESP_OK); + DEBUG_MSG("BLE task exiting\n"); } void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) @@ -760,15 +498,15 @@ void reinitBluetooth() DEBUG_MSG("Starting bluetooth\n"); esp_log_level_set("BTDM_INIT", ESP_LOG_VERBOSE); - if (!bluetoothPhoneAPI) { + auto isFirstTime = !bluetoothPhoneAPI; + + if (isFirstTime) { bluetoothPhoneAPI = new BluetoothPhoneAPI(); bluetoothPhoneAPI->init(); } - // FIXME - if waking from light sleep, only esp_nimble_hci_init - // FIXME - why didn't this version work? - auto res = esp_nimble_hci_and_controller_init(); - // auto res = esp_nimble_hci_init(); + // FIXME - if waking from light sleep, only esp_nimble_hci_init? + auto res = esp_nimble_hci_and_controller_init(); // : esp_nimble_hci_init(); // DEBUG_MSG("BLE result %d\n", res); assert(res == ESP_OK); @@ -808,5 +546,3 @@ void reinitBluetooth() nimble_port_freertos_init(ble_host_task); } - -#endif From abdc4dfae86266676a932f3b0cc45aeb4868d092 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 21:29:32 -0700 Subject: [PATCH 15/25] remove old mesh ble service --- src/esp32/MeshBluetoothService.cpp | 148 ----------------------------- src/esp32/MeshBluetoothService.h | 14 --- 2 files changed, 162 deletions(-) delete mode 100644 src/esp32/MeshBluetoothService.cpp delete mode 100644 src/esp32/MeshBluetoothService.h diff --git a/src/esp32/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp deleted file mode 100644 index bed17705a..000000000 --- a/src/esp32/MeshBluetoothService.cpp +++ /dev/null @@ -1,148 +0,0 @@ - -#include -#include - -#include "BluetoothCommon.h" -#include "GPS.h" -#include "MeshService.h" -#include "NodeDB.h" -#include "PhoneAPI.h" -#include "PowerFSM.h" -#include "configuration.h" -#include "mesh-pb-constants.h" -#include "mesh.pb.h" - -#ifdef CONFIG_BLUEDROID_ENABLED - -#include -#include -#include "CallbackCharacteristic.h" -#include "BluetoothUtil.h" -#include "MeshBluetoothService.h" - -// 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 CallbackCharacteristic *meshFromNumCharacteristic; - -BLEService *meshService; - -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); - - if (meshFromNumCharacteristic) { // this ptr might change from sleep to sleep, or even be null - meshFromNumCharacteristic->setValue(fromRadioNum); - meshFromNumCharacteristic->notify(); - } - } -}; - -static BluetoothPhoneAPI *bluetoothPhoneAPI; - -class ToRadioCharacteristic : public CallbackCharacteristic -{ - public: - ToRadioCharacteristic() : CallbackCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE) {} - - void onWrite(BLECharacteristic *c) { bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length()); } -}; - -class FromRadioCharacteristic : public CallbackCharacteristic -{ - public: - FromRadioCharacteristic() : CallbackCharacteristic(FROMRADIO_UUID, BLECharacteristic::PROPERTY_READ) {} - - void onRead(BLECharacteristic *c) - { - size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); - - // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue - // or make empty if the queue is empty - if (numBytes) { - c->setValue(trBytes, numBytes); - } else { - c->setValue((uint8_t *)"", 0); - } - } -}; - -class FromNumCharacteristic : public CallbackCharacteristic -{ - public: - FromNumCharacteristic() - : CallbackCharacteristic(FROMNUM_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_NOTIFY) - { - // observe(&service.fromNumChanged); - } - - void onRead(BLECharacteristic *c) { DEBUG_MSG("FIXME implement fromnum read\n"); } -}; - -/* -See bluetooth-api.md for documentation. - */ -BLEService *createMeshBluetoothService(BLEServer *server) -{ - // Only create our phone API object once - if (!bluetoothPhoneAPI) { - bluetoothPhoneAPI = new BluetoothPhoneAPI(); - bluetoothPhoneAPI->init(); - } - - // Create the BLE Service, we need more than the default of 15 handles - BLEService *service = server->createService(BLEUUID(MESH_SERVICE_UUID), 30, 0); - - assert(!meshFromNumCharacteristic); - meshFromNumCharacteristic = new FromNumCharacteristic; - - addWithDesc(service, meshFromNumCharacteristic, "fromRadio"); - addWithDesc(service, new ToRadioCharacteristic, "toRadio"); - addWithDesc(service, new FromRadioCharacteristic, "fromNum"); - - meshFromNumCharacteristic->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification - - service->start(); - - // We only add to advertisting once, because the ESP32 arduino code is dumb and that object never dies - static bool firstTime = true; - if (firstTime) { - firstTime = false; - server->getAdvertising()->addServiceUUID(service->getUUID()); - } - - DEBUG_MSG("*** Mesh service:\n"); - service->dump(); - - meshService = service; - return service; -} - -void stopMeshBluetoothService() -{ - assert(meshService); - meshService->stop(); - meshService->executeDelete(); -} - -void destroyMeshBluetoothService() -{ - assert(meshService); - delete meshService; - - meshFromNumCharacteristic = NULL; -} - -#else - -void destroyMeshBluetoothService() {} -void stopMeshBluetoothService() {} - -#endif \ No newline at end of file diff --git a/src/esp32/MeshBluetoothService.h b/src/esp32/MeshBluetoothService.h deleted file mode 100644 index c0a95a0b6..000000000 --- a/src/esp32/MeshBluetoothService.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef CONFIG_BLUEDROID_ENABLED - -BLEService *createMeshBluetoothService(BLEServer *server); - -#endif - -void destroyMeshBluetoothService(); -void stopMeshBluetoothService(); \ No newline at end of file From 107b56a34659523b4dfd847826a03e4208c18f01 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 21:41:56 -0700 Subject: [PATCH 16/25] move bluetooth enable --- src/esp32/main-esp32.cpp | 25 ------------------------ src/nimble/BluetoothUtil.cpp | 37 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index 5936e8c8e..d74bda988 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -1,4 +1,3 @@ -#include "MeshBluetoothService.h" #include "PowerFSM.h" #include "configuration.h" #include "esp_task_wdt.h" @@ -10,30 +9,6 @@ #include #include -bool bluetoothOn; - -// Enable/disable bluetooth. -void setBluetoothEnable(bool on) -{ - if (on != bluetoothOn) { - DEBUG_MSG("Setting bluetooth enable=%d\n", on); - - bluetoothOn = on; - if (on) { - Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap()); - // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); - reinitBluetooth(); - } else { - // We have to totally teardown our bluetooth objects to prevent leaks - stopMeshBluetoothService(); // Must do before shutting down bluetooth - deinitBLE(); - destroyMeshBluetoothService(); // must do after deinit, because it frees our service - Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap()); - // ESP_ERROR_CHECK( heap_trace_stop() ); - // heap_trace_dump(); - } - } -} void getMacAddr(uint8_t *dmac) { diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 81eb2bfad..558ffb500 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -1,6 +1,7 @@ #include "BluetoothUtil.h" #include "BluetoothSoftwareUpdate.h" #include "configuration.h" +#include "esp_bt.h" #include #include #include @@ -179,7 +180,10 @@ void deinitBLE() ret = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers assert(ret == ESP_OK); - +#if 0 + auto ret = esp_bt_controller_disable(); + assert(ret == ESP_OK); +#endif DEBUG_MSG("Done shutting down bluetooth\n"); } @@ -495,11 +499,9 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) // This routine is called multiple times, once each time we come back from sleep void reinitBluetooth() { - DEBUG_MSG("Starting bluetooth\n"); - esp_log_level_set("BTDM_INIT", ESP_LOG_VERBOSE); - auto isFirstTime = !bluetoothPhoneAPI; + DEBUG_MSG("Starting bluetooth\n"); if (isFirstTime) { bluetoothPhoneAPI = new BluetoothPhoneAPI(); bluetoothPhoneAPI->init(); @@ -530,8 +532,8 @@ void reinitBluetooth() ble_svc_gap_init(); ble_svc_gatt_init(); - res = ble_gatts_count_cfg( - gatt_svr_svcs); // assigns handles? see docstring for note about clearing the handle list before calling SLEEP SUPPORT + res = ble_gatts_count_cfg(gatt_svr_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_svr_svcs); @@ -546,3 +548,26 @@ void reinitBluetooth() nimble_port_freertos_init(ble_host_task); } + +bool bluetoothOn; + +// Enable/disable bluetooth. +void setBluetoothEnable(bool on) +{ + if (on != bluetoothOn) { + DEBUG_MSG("Setting bluetooth enable=%d\n", on); + + bluetoothOn = on; + if (on) { + Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap()); + // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); + reinitBluetooth(); + } else { + // We have to totally teardown our bluetooth objects to prevent leaks + deinitBLE(); + Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap()); + // ESP_ERROR_CHECK( heap_trace_stop() ); + // heap_trace_dump(); + } + } +} From 4eb27b637d4eaccf7375a2157dc9ddd8ae2fd884 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 22 Jul 2020 22:13:53 -0700 Subject: [PATCH 17/25] Nimble sleep now works nicely --- docs/software/TODO.md | 2 -- src/nimble/BluetoothUtil.cpp | 30 ++++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index e35526a98..c638a34b4 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -5,8 +5,6 @@ You probably don't care about this section - skip to the next one. Nimble tasks: - restart advertising after client disconnects (confirm this works if client goes out of range) -- make sleep work -- check BLE handle stability - started RPA long test, jul 22 6pm - implement nimble software update api - implement nimble battery level service diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 558ffb500..6d1f0076d 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -122,7 +122,7 @@ int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt return BLE_ATT_ERR_UNLIKELY; } - DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len); + /// DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len); bluetoothPhoneAPI->handleToRadio(trBytes, len); return 0; @@ -130,7 +130,7 @@ int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - DEBUG_MSG("BLE fromRadio called\n"); + /// DEBUG_MSG("BLE fromRadio called\n"); size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue @@ -143,7 +143,7 @@ int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - DEBUG_MSG("BLE fromNum called\n"); + // DEBUG_MSG("BLE fromNum called\n"); auto rc = os_mbuf_append(ctxt->om, &fromNum, sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness assert(rc == 0); @@ -165,25 +165,22 @@ void updateBatteryLevel(uint8_t level) void deinitBLE() { - DEBUG_MSG("Shutting down bluetooth\n"); - ble_gatts_show_local(); + // DEBUG_MSG("Shutting down bluetooth\n"); + // ble_gatts_show_local(); // FIXME - do we need to dealloc things? - what needs to stay alive across light sleep? auto ret = nimble_port_stop(); assert(ret == ESP_OK); - nimble_port_deinit(); // teardown nimble datastructures - nimble_port_freertos_deinit(); // delete the task + nimble_port_deinit(); // teardown nimble datastructures + + // DEBUG_MSG("BLE port_deinit done\n"); ret = esp_nimble_hci_and_controller_deinit(); assert(ret == ESP_OK); - ret = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers - assert(ret == ESP_OK); -#if 0 - auto ret = esp_bt_controller_disable(); - assert(ret == ESP_OK); -#endif + // DEBUG_MSG("BLE task exiting\n"); + DEBUG_MSG("Done shutting down bluetooth\n"); } @@ -463,7 +460,9 @@ static void ble_host_task(void *param) DEBUG_MSG("BLE task running\n"); nimble_port_run(); // This function will return only when nimble_port_stop() is executed. - DEBUG_MSG("BLE task exiting\n"); + DEBUG_MSG("BLE run complete\n"); + + nimble_port_freertos_deinit(); // delete the task } void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) @@ -514,6 +513,9 @@ void reinitBluetooth() nimble_port_init(); + res = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers + assert(res == ESP_OK); + /* Initialize the NimBLE host configuration. */ ble_hs_cfg.reset_cb = on_reset; ble_hs_cfg.sync_cb = on_sync; From 0415a3c369f2fc565cf4d986c0fd36e697d5ae67 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 23 Jul 2020 08:10:36 -0700 Subject: [PATCH 18/25] Clean up nimble files --- src/main.cpp | 34 ----- src/nimble/BluetoothUtil.cpp | 206 ++++++++++++------------------ src/nimble/NimbleBluetoothAPI.cpp | 69 ++++++++++ src/nimble/NimbleBluetoothAPI.h | 18 +++ 4 files changed, 168 insertions(+), 159 deletions(-) create mode 100644 src/nimble/NimbleBluetoothAPI.cpp create mode 100644 src/nimble/NimbleBluetoothAPI.h diff --git a/src/main.cpp b/src/main.cpp index dfbe7288d..3d5dd6975 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,7 +43,6 @@ // #include #ifndef NO_ESP32 -#include "WiFi.h" #include "nimble/BluetoothUtil.h" #endif @@ -149,35 +148,6 @@ void userButtonPressedLong() screen.adjustBrightness(); } -#ifndef NO_ESP32 -void initWifi() -{ -#if 0 - // strcpy(radioConfig.preferences.wifi_ssid, "xxx"); - // strcpy(radioConfig.preferences.wifi_password, "xxx"); - if (radioConfig.has_preferences) { - const char *wifiName = radioConfig.preferences.wifi_ssid; - - if (*wifiName) { - const char *wifiPsw = radioConfig.preferences.wifi_password; - if (radioConfig.preferences.wifi_ap_mode) { - DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw)); - } else { - WiFi.mode(WIFI_MODE_STA); - DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName); - if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) { - DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str()); - } else { - DEBUG_MSG("FAILED JOINING WIFI\n"); - } - } - } - } else - DEBUG_MSG("Not using WIFI\n"); -#endif -} -#endif - void setup() { #ifdef USE_SEGGER @@ -286,10 +256,6 @@ void setup() nodeStatus->observe(&nodeDB.newStatus); service.init(); -#ifndef NO_ESP32 - // Must be after we init the service, because the wifi settings are loaded by NodeDB (oops) - initWifi(); -#endif #ifdef SX1262_ANT_SW // make analog PA vs not PA switch on SX1262 eval board work properly diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 6d1f0076d..83386542d 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -1,65 +1,18 @@ #include "BluetoothUtil.h" #include "BluetoothSoftwareUpdate.h" -#include "configuration.h" -#include "esp_bt.h" -#include -#include -#include -#include - -#if 0 - -static BLECharacteristic *batteryLevelC; - -/** - * Create a battery level service - */ -BLEService *createBatteryService(BLEServer *server) -{ - // Create the BLE Service - BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F)); - - batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL), - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); - - addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100"); - batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification - - // I don't think we need to advertise this? and some phones only see the first thing advertised anyways... - // server->getAdvertising()->addServiceUUID(pBattery->getUUID()); - pBattery->start(); - - return pBattery; -} - -/** - * Update the battery level we are currently telling clients. - * level should be a pct between 0 and 100 - */ -void updateBatteryLevel(uint8_t level) -{ - if (batteryLevelC) { - DEBUG_MSG("set BLE battery level %u\n", level); - batteryLevelC->setValue(&level, 1); - batteryLevelC->notify(); - } -} - - - -// Note: these callbacks might be coming in from a different thread. -BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION), - optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr - -#endif - +#include "NimbleBluetoothAPI.h" +#include "NodeDB.h" // FIXME - we shouldn't really douch this here - we are using it only because we currently do wifi setup when ble gets turned on #include "PhoneAPI.h" #include "PowerFSM.h" +#include "WiFi.h" +#include "configuration.h" +#include "esp_bt.h" #include "host/util/util.h" #include "main.h" #include "nimble/NimbleDefs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" +#include static bool pinShowing; @@ -80,77 +33,6 @@ static void stopCb() static uint8_t own_addr_type; -// 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(FromRadio_size, ToRadio_size)]; - -static uint16_t fromNumValHandle; -static uint32_t fromNum; - -/// We only allow one BLE connection at a time -static int16_t curConnectionHandle = -1; - -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); - - fromNum = fromRadioNum; - if (curConnectionHandle >= 0 && fromNumValHandle) { - DEBUG_MSG("BLE notify fromNum\n"); - auto res = ble_gattc_notify(curConnectionHandle, fromNumValHandle); - assert(res == 0); - } else { - DEBUG_MSG("No BLE notify\n"); - } - } -}; - -static BluetoothPhoneAPI *bluetoothPhoneAPI; - -int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - auto om = ctxt->om; - uint16_t len = 0; - - auto rc = ble_hs_mbuf_to_flat(om, trBytes, sizeof(trBytes), &len); - if (rc != 0) { - return BLE_ATT_ERR_UNLIKELY; - } - - /// DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len); - - bluetoothPhoneAPI->handleToRadio(trBytes, len); - return 0; -} - -int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - /// DEBUG_MSG("BLE fromRadio called\n"); - size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); - - // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue - // or make empty if the queue is empty - auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes); - assert(rc == 0); - - return 0; // success -} - -int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - // DEBUG_MSG("BLE fromNum called\n"); - auto rc = os_mbuf_append(ctxt->om, &fromNum, - sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness - assert(rc == 0); - - return 0; // success -} - // Force arduino to keep ble data around extern "C" bool btInUse() { @@ -460,7 +342,7 @@ static void ble_host_task(void *param) DEBUG_MSG("BLE task running\n"); nimble_port_run(); // This function will return only when nimble_port_stop() is executed. - DEBUG_MSG("BLE run complete\n"); + // DEBUG_MSG("BLE run complete\n"); nimble_port_freertos_deinit(); // delete the task } @@ -551,6 +433,32 @@ void reinitBluetooth() nimble_port_freertos_init(ble_host_task); } +void initWifi() +{ + // Note: Wifi is not yet supported ;-) + strcpy(radioConfig.preferences.wifi_ssid, ""); + strcpy(radioConfig.preferences.wifi_password, ""); + if (radioConfig.has_preferences) { + const char *wifiName = radioConfig.preferences.wifi_ssid; + + if (*wifiName) { + const char *wifiPsw = radioConfig.preferences.wifi_password; + if (radioConfig.preferences.wifi_ap_mode) { + DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw)); + } else { + WiFi.mode(WIFI_MODE_STA); + DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName); + if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) { + DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str()); + } else { + DEBUG_MSG("Started Joining WIFI\n"); + } + } + } + } else + DEBUG_MSG("Not using WIFI\n"); +} + bool bluetoothOn; // Enable/disable bluetooth. @@ -564,12 +472,60 @@ void setBluetoothEnable(bool on) Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap()); // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); reinitBluetooth(); + initWifi(); } else { // We have to totally teardown our bluetooth objects to prevent leaks deinitBLE(); + WiFi.mode(WIFI_MODE_NULL); // shutdown wifi Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap()); // ESP_ERROR_CHECK( heap_trace_stop() ); // heap_trace_dump(); } } } + +#if 0 + +static BLECharacteristic *batteryLevelC; + +/** + * Create a battery level service + */ +BLEService *createBatteryService(BLEServer *server) +{ + // Create the BLE Service + BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F)); + + batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL), + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); + + addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100"); + batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification + + // I don't think we need to advertise this? and some phones only see the first thing advertised anyways... + // server->getAdvertising()->addServiceUUID(pBattery->getUUID()); + pBattery->start(); + + return pBattery; +} + +/** + * Update the battery level we are currently telling clients. + * level should be a pct between 0 and 100 + */ +void updateBatteryLevel(uint8_t level) +{ + if (batteryLevelC) { + DEBUG_MSG("set BLE battery level %u\n", level); + batteryLevelC->setValue(&level, 1); + batteryLevelC->notify(); + } +} + + + +// Note: these callbacks might be coming in from a different thread. +BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION), + optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr + +#endif \ No newline at end of file diff --git a/src/nimble/NimbleBluetoothAPI.cpp b/src/nimble/NimbleBluetoothAPI.cpp new file mode 100644 index 000000000..0de53e814 --- /dev/null +++ b/src/nimble/NimbleBluetoothAPI.cpp @@ -0,0 +1,69 @@ +#include "NimbleBluetoothAPI.h" +#include "PhoneAPI.h" +#include "configuration.h" +#include "nimble/NimbleDefs.h" + +// 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(FromRadio_size, ToRadio_size)]; +static uint32_t fromNum; + +uint16_t fromNumValHandle; + +/// We only allow one BLE connection at a time +int16_t curConnectionHandle = -1; + +PhoneAPI *bluetoothPhoneAPI; + +void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum) +{ + PhoneAPI::onNowHasData(fromRadioNum); + + fromNum = fromRadioNum; + if (curConnectionHandle >= 0 && fromNumValHandle) { + DEBUG_MSG("BLE notify fromNum\n"); + auto res = ble_gattc_notify(curConnectionHandle, fromNumValHandle); + assert(res == 0); + } else { + DEBUG_MSG("No BLE notify\n"); + } +} + +int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + auto om = ctxt->om; + uint16_t len = 0; + + auto rc = ble_hs_mbuf_to_flat(om, trBytes, sizeof(trBytes), &len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + /// DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len); + + bluetoothPhoneAPI->handleToRadio(trBytes, len); + return 0; +} + +int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + /// DEBUG_MSG("BLE fromRadio called\n"); + size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); + + // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue + // or make empty if the queue is empty + auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes); + assert(rc == 0); + + return 0; // success +} + +int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + // DEBUG_MSG("BLE fromNum called\n"); + auto rc = os_mbuf_append(ctxt->om, &fromNum, + sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness + assert(rc == 0); + + return 0; // success +} diff --git a/src/nimble/NimbleBluetoothAPI.h b/src/nimble/NimbleBluetoothAPI.h new file mode 100644 index 000000000..419bf0e0a --- /dev/null +++ b/src/nimble/NimbleBluetoothAPI.h @@ -0,0 +1,18 @@ +#pragma once + +#include "PhoneAPI.h" + +extern uint16_t fromNumValHandle; + +/// We only allow one BLE connection at a time +extern int16_t curConnectionHandle; + +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); +}; + +extern PhoneAPI *bluetoothPhoneAPI; \ No newline at end of file From 00ca351169a2738a39702c99e0e293e918c9cfc2 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 23 Jul 2020 08:37:00 -0700 Subject: [PATCH 19/25] WIP begin changing software update service over to nimble --- src/esp32/BluetoothSoftwareUpdate.cpp | 211 +++++++++----------------- src/esp32/BluetoothSoftwareUpdate.h | 27 +++- src/esp32/NimbleSoftwareUpdate.c | 61 ++++++++ src/esp32/main-esp32.cpp | 3 +- src/nimble/NimbleDefs.c | 13 +- 5 files changed, 158 insertions(+), 157 deletions(-) create mode 100644 src/esp32/NimbleSoftwareUpdate.c diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 7477ded05..d970f1c03 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -1,130 +1,106 @@ #include -#ifdef CONFIG_BLUEDROID_ENABLED - #include "../concurrency/LockGuard.h" #include "../timing.h" #include "BluetoothSoftwareUpdate.h" -#include "BluetoothUtil.h" #include "RadioLibInterface.h" #include "configuration.h" -#include #include #include -#include #include "CallbackCharacteristic.h" -CRC32 crc; -uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) +int16_t updateResultHandle; -uint32_t updateExpectedSize, updateActualSize; +static CRC32 crc; +static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) -concurrency::Lock *updateLock; +static uint32_t updateExpectedSize, updateActualSize; -class TotalSizeCharacteristic : public CallbackCharacteristic +static concurrency::Lock *updateLock; + +/// Handle writes & reads to total size +int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - public: - TotalSizeCharacteristic() - : CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e", - BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ) - { - } + concurrency::LockGuard g(updateLock); + // Check if there is enough to OTA Update + uint32_t len = getValue32(c, 0); + updateExpectedSize = len; + updateActualSize = 0; + crc.reset(); + bool canBegin = Update.begin(len); + DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin); + if (!canBegin) { + // Indicate failure by forcing the size to 0 + uint32_t zero = 0; + c->setValue(zero); + } 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(); - void onWrite(BLECharacteristic *c) - { - concurrency::LockGuard g(updateLock); - // Check if there is enough to OTA Update - uint32_t len = getValue32(c, 0); - updateExpectedSize = len; - updateActualSize = 0; - crc.reset(); - bool canBegin = Update.begin(len); - DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin); - if (!canBegin) { - // Indicate failure by forcing the size to 0 - uint32_t zero = 0; - c->setValue(zero); - } 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(); - - if (RadioLibInterface::instance) - RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are - // writing flash - shut the radio off during updates - } + if (RadioLibInterface::instance) + RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are + // writing flash - shut the radio off during updates } -}; +} #define MAX_BLOCKSIZE 512 -class DataCharacteristic : public CallbackCharacteristic +/// Handle writes to data +int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - public: - DataCharacteristic() : CallbackCharacteristic("e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE) {} + concurrency::LockGuard g(updateLock); + std::string value = c->getValue(); + uint32_t len = value.length(); + assert(len <= MAX_BLOCKSIZE); + static uint8_t + data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf + memcpy(data, c->getData(), len); + // DEBUG_MSG("Writing %u\n", len); + crc.update(data, len); + Update.write(data, len); + updateActualSize += len; + powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now +} - void onWrite(BLECharacteristic *c) - { - concurrency::LockGuard g(updateLock); - std::string value = c->getValue(); - uint32_t len = value.length(); - assert(len <= MAX_BLOCKSIZE); - static uint8_t - data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf - memcpy(data, c->getData(), len); - // DEBUG_MSG("Writing %u\n", len); - crc.update(data, len); - Update.write(data, len); - updateActualSize += len; - powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now - } -}; - -static BLECharacteristic *resultC; - -class CRC32Characteristic : public CallbackCharacteristic +/// Handle writes to crc32 +int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - public: - CRC32Characteristic() : CallbackCharacteristic("4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE) {} + concurrency::LockGuard g(updateLock); + uint32_t expectedCRC = getValue32(c, 0); + uint32_t actualCRC = crc.finalize(); + DEBUG_MSG("expected CRC %u\n", expectedCRC); - void onWrite(BLECharacteristic *c) + 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. { - concurrency::LockGuard g(updateLock); - uint32_t expectedCRC = getValue32(c, 0); - 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 + DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC); + result = 0xe0; // FIXME, use real error codes + } else { + if (Update.end()) { + DEBUG_MSG("OTA done, rebooting in 5 seconds!\n"); + rebootAtMsec = timing::millis() + 5000; } else { - if (Update.end()) { - DEBUG_MSG("OTA done, rebooting in 5 seconds!\n"); - rebootAtMsec = timing::millis() + 5000; - } else { - DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError()); - } - result = Update.getError(); + DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError()); } - - if (RadioLibInterface::instance) - RadioLibInterface::instance->startReceive(); // Resume radio - - assert(resultC); - resultC->setValue(&result, 1); - resultC->notify(); + result = Update.getError(); } -}; + + if (RadioLibInterface::instance) + RadioLibInterface::instance->startReceive(); // Resume radio + + assert(resultC); + resultC->setValue(&result, 1); + resultC->notify(); +} void bluetoothRebootCheck() { @@ -138,47 +114,8 @@ void bluetoothRebootCheck() See bluetooth-api.md */ -BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion) +void createUpdateService() { if (!updateLock) updateLock = new concurrency::Lock(); - - // Create the BLE Service - BLEService *service = server->createService(BLEUUID("cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"), 25, 0); - - assert(!resultC); - resultC = new BLECharacteristic("5e134862-7411-4424-ac4a-210937432c77", - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); - - addWithDesc(service, new TotalSizeCharacteristic, "total image size"); - addWithDesc(service, new DataCharacteristic, "data"); - addWithDesc(service, new CRC32Characteristic, "crc32"); - addWithDesc(service, resultC, "result code"); - - resultC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification - - BLECharacteristic *swC = - new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ); - swC->setValue(swVersion); - service->addCharacteristic(addBLECharacteristic(swC)); - - BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ); - mfC->setValue(hwVendor); - service->addCharacteristic(addBLECharacteristic(mfC)); - - BLECharacteristic *hwvC = - new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ); - hwvC->setValue(hwVersion); - service->addCharacteristic(addBLECharacteristic(hwvC)); - - return service; } - -void destroyUpdateService() -{ - assert(resultC); - - resultC = NULL; -} - -#endif diff --git a/src/esp32/BluetoothSoftwareUpdate.h b/src/esp32/BluetoothSoftwareUpdate.h index 80b32ffc0..1efec3d11 100644 --- a/src/esp32/BluetoothSoftwareUpdate.h +++ b/src/esp32/BluetoothSoftwareUpdate.h @@ -1,15 +1,26 @@ #pragma once -#include -#include -#include -#include +#include "nimble/NimbleDefs.h" -#ifdef CONFIG_BLUEDROID_ENABLED +void createUpdateService(); -BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion); - -void destroyUpdateService(); void bluetoothRebootCheck(); +#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); + +extern const struct ble_gatt_svc_def gatt_update_svcs[]; + +extern const ble_uuid128_t update_result_uuid; + +extern int16_t updateResultHandle; + +#ifdef __cplusplus +}; #endif \ No newline at end of file diff --git a/src/esp32/NimbleSoftwareUpdate.c b/src/esp32/NimbleSoftwareUpdate.c new file mode 100644 index 000000000..e02cd4a9d --- /dev/null +++ b/src/esp32/NimbleSoftwareUpdate.c @@ -0,0 +1,61 @@ +#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); + +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_size_callback, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY, + }, + { + 0, /* No more characteristics in this service. */ + }}, + }, + + { + 0, /* No more services. */ + }, +}; diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index d74bda988..aa85f9524 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -1,3 +1,4 @@ +#include "BluetoothSoftwareUpdate.h" #include "PowerFSM.h" #include "configuration.h" #include "esp_task_wdt.h" @@ -9,7 +10,6 @@ #include #include - void getMacAddr(uint8_t *dmac) { assert(esp_efuse_mac_get_default(dmac) == ESP_OK); @@ -82,6 +82,7 @@ void esp32Loop() { esp_task_wdt_reset(); // service our app level watchdog loopBLE(); + bluetoothRebootCheck(); // for debug printing // radio.radioIf.canSleep(); diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c index fb9d55188..179cbebf6 100644 --- a/src/nimble/NimbleDefs.c +++ b/src/nimble/NimbleDefs.c @@ -1,15 +1,7 @@ #include "NimbleDefs.h" -// A C++ version of BLE_UUID128_INIT -#define BLE_UUID128_INIT_CPP(uuid128...) \ - { \ - u : { \ - type: \ - BLE_UUID_TYPE_128 \ - } \ - , value: { uuid128 } \ - } - +// NRF52 wants these constants as byte arrays +// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER const ble_uuid128_t mesh_service_uuid = BLE_UUID128_INIT(0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b); @@ -29,7 +21,6 @@ const struct ble_gatt_svc_def gatt_svr_svcs[] = { .uuid = &mesh_service_uuid.u, .characteristics = (struct ble_gatt_chr_def[]){{ - // FIXME - remove non ENC access .uuid = &toradio_uuid.u, .access_cb = toradio_callback, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN, From b0e2c81666b9441b60d8a88af7c5e15fb2702c5e Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 23 Jul 2020 15:34:54 -0700 Subject: [PATCH 20/25] nimble software update WIP builds --- src/esp32/BluetoothSoftwareUpdate.cpp | 90 +++++++++++++++++---------- src/nimble/BluetoothUtil.cpp | 66 ++++++++++++++++++++ src/nimble/BluetoothUtil.h | 47 +++++--------- src/nimble/NimbleBluetoothAPI.cpp | 11 ++-- src/nimble/NimbleBluetoothAPI.h | 3 - src/nimble/NimbleDefs.h | 7 +++ 6 files changed, 150 insertions(+), 74 deletions(-) diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index d970f1c03..5aa073a11 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -3,15 +3,15 @@ #include "../concurrency/LockGuard.h" #include "../timing.h" #include "BluetoothSoftwareUpdate.h" +#include "PowerFSM.h" #include "RadioLibInterface.h" #include "configuration.h" +#include "nimble/BluetoothUtil.h" #include #include -#include "CallbackCharacteristic.h" - -int16_t updateResultHandle; +int16_t updateResultHandle = -1; static CRC32 crc; static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) @@ -21,57 +21,70 @@ static uint32_t updateExpectedSize, updateActualSize; static concurrency::Lock *updateLock; /// Handle writes & reads to total size -int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +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 - uint32_t len = getValue32(c, 0); - updateExpectedSize = len; - updateActualSize = 0; - crc.reset(); - bool canBegin = Update.begin(len); - DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin); - if (!canBegin) { - // Indicate failure by forcing the size to 0 - uint32_t zero = 0; - c->setValue(zero); - } 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(); - if (RadioLibInterface::instance) - RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are - // writing flash - shut the radio off during updates + // Check if there is enough to OTA Update + chr_readwrite32le(&updateExpectedSize, ctxt, arg); + + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) { + updateActualSize = 0; + crc.reset(); + bool canBegin = Update.begin(updateExpectedSize); + DEBUG_MSG("Setting update size %u, result %d\n", 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(); + + if (RadioLibInterface::instance) + RadioLibInterface::instance->sleep(); // 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 512 /// Handle writes to data -int totalSize_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) { concurrency::LockGuard g(updateLock); - std::string value = c->getValue(); - uint32_t len = value.length(); - assert(len <= MAX_BLOCKSIZE); + static uint8_t data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf - memcpy(data, c->getData(), len); + + 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_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now + + return 0; } +static uint8_t update_result; + /// Handle writes to crc32 -int totalSize_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) { concurrency::LockGuard g(updateLock); - uint32_t expectedCRC = getValue32(c, 0); + uint32_t expectedCRC = 0; + chr_readwrite32le(&expectedCRC, ctxt, arg); + uint32_t actualCRC = crc.finalize(); DEBUG_MSG("expected CRC %u\n", expectedCRC); @@ -97,9 +110,18 @@ int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga if (RadioLibInterface::instance) RadioLibInterface::instance->startReceive(); // Resume radio - assert(resultC); - resultC->setValue(&result, 1); - resultC->notify(); + 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, arg); } void bluetoothRebootCheck() diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 83386542d..29a7f22d0 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -365,6 +365,10 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) fromNumValHandle = ctxt->chr.val_handle; DEBUG_MSG("FromNum handle %d\n", fromNumValHandle); } + if (ctxt->chr.chr_def->uuid == &update_result_uuid.u) { + updateResultHandle = ctxt->chr.val_handle; + DEBUG_MSG("update result handle %d\n", updateResultHandle); + } break; case BLE_GATT_REGISTER_OP_DSC: @@ -377,6 +381,68 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) } } +/** + * A helper function that implements simple read and write handling for a uint32_t + * + * 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. + */ +int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint8_t le[4]; + + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + DEBUG_MSG("BLE reading a uint32\n"); + put_le32(le, *v); + auto rc = os_mbuf_append(ctxt->om, le, sizeof(le)); + assert(rc == 0); + } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + uint16_t len = 0; + + auto rc = ble_hs_mbuf_to_flat(ctxt->om, le, sizeof(le), &len); + assert(rc == 0); + if (len < sizeof(le)) { + DEBUG_MSG("Error: wrongsized write32\n"); + *v = 0; + } else { + *v = get_le32(le); + DEBUG_MSG("BLE writing a uint32\n"); + } + } else { + DEBUG_MSG("Unexpected readwrite32 op\n"); + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; // success +} + +/** + * 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, void *arg) +{ + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + DEBUG_MSG("BLE reading bytes\n"); + auto rc = os_mbuf_append(ctxt->om, v, vlen); + assert(rc == 0); + } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + uint16_t len = 0; + + auto rc = ble_hs_mbuf_to_flat(ctxt->om, v, vlen, &len); + assert(rc == 0); + if (len < vlen) + DEBUG_MSG("Error: wrongsized write\n"); + else { + DEBUG_MSG("BLE writing bytes\n"); + } + } else { + DEBUG_MSG("Unexpected readwrite8 op\n"); + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; // success +} + // This routine is called multiple times, once each time we come back from sleep void reinitBluetooth() { diff --git a/src/nimble/BluetoothUtil.h b/src/nimble/BluetoothUtil.h index 8330afc47..7a1c62463 100644 --- a/src/nimble/BluetoothUtil.h +++ b/src/nimble/BluetoothUtil.h @@ -1,36 +1,10 @@ #pragma once +#include #include -#include "SimpleAllocator.h" -#include -#include -#include -#include - -#ifdef CONFIG_BLUEDROID_ENABLED - -// Help routine to add a description to any BLECharacteristic and add it to the service -void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description); - -void dumpCharacteristic(BLECharacteristic *c); - -/** converting endianness pull out a 32 bit value */ -uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue); - -BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen, - std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); - -/// Add a characteristic that we will delete when we restart -BLECharacteristic *addBLECharacteristic(BLECharacteristic *c); - -/// Add a characteristic that we will delete when we restart -BLEDescriptor *addBLEDescriptor(BLEDescriptor *c); - -/// Any bluetooth objects you allocate _must_ come from this pool if you want to be able to call deinitBLE() -extern SimpleAllocator btPool; - -#endif +/// We only allow one BLE connection at a time +extern int16_t curConnectionHandle; // TODO(girts): create a class for the bluetooth utils helpers? using StartBluetoothPinScreenCallback = std::function; @@ -40,4 +14,17 @@ using StopBluetoothPinScreenCallback = std::function; void updateBatteryLevel(uint8_t level); void deinitBLE(); void loopBLE(); -void reinitBluetooth(); \ No newline at end of file +void reinitBluetooth(); + +/** + * A helper function that implements simple read and write handling for a uint32_t + * + * 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. + */ +int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg); + +/** + * 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, void *arg); \ No newline at end of file diff --git a/src/nimble/NimbleBluetoothAPI.cpp b/src/nimble/NimbleBluetoothAPI.cpp index 0de53e814..a093cbf5d 100644 --- a/src/nimble/NimbleBluetoothAPI.cpp +++ b/src/nimble/NimbleBluetoothAPI.cpp @@ -1,11 +1,13 @@ #include "NimbleBluetoothAPI.h" #include "PhoneAPI.h" #include "configuration.h" +#include "nimble/BluetoothUtil.h" #include "nimble/NimbleDefs.h" +#include // 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(FromRadio_size, ToRadio_size)]; +static uint8_t trBytes[FromRadio_size < ToRadio_size ? ToRadio_size : FromRadio_size]; static uint32_t fromNum; uint16_t fromNumValHandle; @@ -60,10 +62,5 @@ int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - // DEBUG_MSG("BLE fromNum called\n"); - auto rc = os_mbuf_append(ctxt->om, &fromNum, - sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness - assert(rc == 0); - - return 0; // success + return chr_readwrite32le(&fromNum, ctxt, arg); } diff --git a/src/nimble/NimbleBluetoothAPI.h b/src/nimble/NimbleBluetoothAPI.h index 419bf0e0a..5fa66cc24 100644 --- a/src/nimble/NimbleBluetoothAPI.h +++ b/src/nimble/NimbleBluetoothAPI.h @@ -4,9 +4,6 @@ extern uint16_t fromNumValHandle; -/// We only allow one BLE connection at a time -extern int16_t curConnectionHandle; - class BluetoothPhoneAPI : public PhoneAPI { /** diff --git a/src/nimble/NimbleDefs.h b/src/nimble/NimbleDefs.h index 8af85c4cb..6b1db22e5 100644 --- a/src/nimble/NimbleDefs.h +++ b/src/nimble/NimbleDefs.h @@ -1,10 +1,17 @@ #pragma once +// Keep nimble #defs from messing up the build +#ifndef max +#define max max +#define min min +#endif + #include "esp_nimble_hci.h" #include "host/ble_hs.h" #include "host/ble_uuid.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" +#include #ifdef __cplusplus extern "C" { From a5b7501a4ec16f794d410ff386e97b0e58a02a6d Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 24 Jul 2020 10:12:25 -0700 Subject: [PATCH 21/25] nimble add debug output --- docs/software/TODO.md | 102 +++++++++++++++++++++++++- src/esp32/BluetoothSoftwareUpdate.cpp | 6 +- src/mesh/NodeDB.cpp | 2 +- src/mesh/NodeDB.h | 2 +- src/nimble/BluetoothUtil.cpp | 4 +- src/nimble/BluetoothUtil.h | 4 +- src/nimble/NimbleBluetoothAPI.cpp | 6 +- 7 files changed, 113 insertions(+), 13 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index c638a34b4..8f32024bf 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,11 +4,107 @@ You probably don't care about this section - skip to the next one. Nimble tasks: +- packets >= 79 bytes (FromRadio) cause INVALID_OFFSET (7) gatt errors to be sent to the app + FIXME - add instrumentation + is MTU setting heppening ever? or only on the first attempt? + client is reading nodeinfos. do we do a second 79 byte read, and that one returns 7 because the length is weong? when the second read should have been 72 bytes? + hmm rebooting did not fix + + disconnecting the app and reconnecting it (on the settings screen) did fix it. So is the android app confused? + is the retry on exception thing not tearing enough down? + + could old reads from a previous session be coming back and messing up new reads? do we need to cancel all pending Jobs? + use reliable writes? < I don't think that is the problem? > + +BLE fromRadio called +getFromRadio, !available +toRadioWriteCb data 0x3ffc3d72, len 4 +Trigger powerFSM 9 +Client wants config, nonce=3494 +Reset nodeinfo read pointer +toRadioWriteCb data 0x3ffc3d72, len 4 +Trigger powerFSM 9 +Client wants config, nonce=3493 +Reset nodeinfo read pointer +BLE fromRadio called +getFromRadio, state=2 +encoding toPhone packet to phone variant=3, 50 bytes +BLE fromRadio called +getFromRadio, state=3 +encoding toPhone packet to phone variant=6, 83 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xabdddf38, lastseen=1594754867, id=!2462abdddf38, name=Bob b +encoding toPhone packet to phone variant=4, 67 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0x28b200b4, lastseen=1595545403, id=!246f28b200b4, name=Unknown 00b4 +encoding toPhone packet to phone variant=4, 79 bytes \*\*\*\* +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xabf84098, lastseen=1593680756, id=!2462abf84098, name=bx n +encoding toPhone packet to phone variant=4, 72 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0x83f0d8e5, lastseen=1594686931, id=!e8e383f0d8e5, name=Unknown d8e5 +encoding toPhone packet to phone variant=4, 64 bytes +BLE fromRadio called +getFromRadio, state=4 +Done sending nodeinfos +getFromRadio, state=5 + +2020-07-23 16:52:47.843 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.RadioInterfaceService: Broadcasting connection=true +2020-07-23 16:52:47.845 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:47.845 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:47.846 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED +2020-07-23 16:52:47.847 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED +2020-07-23 16:52:47.847 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=4091 +2020-07-23 16:52:47.849 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:47.849 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED +2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED +2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=4090 +2020-07-23 16:52:47.852 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: device sleep timeout cancelled +2020-07-23 16:52:47.853 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:47.853 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:48.294 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:48.296 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@1717693 +2020-07-23 16:52:48.296 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 79 bytes from radio +2020-07-23 16:52:48.299 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:48.300 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-23 16:52:48.301 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) +2020-07-23 16:52:48.301 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-23 16:52:48.302 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) +2020-07-23 16:52:48.384 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth\$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +... +07-23 16:52:48.302 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) +2020-07-23 16:52:48.384 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed +2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:48.474 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:48.476 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 +2020-07-23 16:52:48.476 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed +2020-07-23 16:52:48.833 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:48.835 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@1717693 +2020-07-23 16:52:48.835 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 79 bytes from radio +2020-07-23 16:52:48.837 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:48.839 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-23 16:52:48.840 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) +2020-07-23 16:52:48.840 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-23 16:52:48.842 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) +2020-07-23 16:52:49.104 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:49.106 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=7, res=android.bluetooth.BluetoothGattCharacteristic@1717693 +2020-07-23 16:52:49.107 6478-27868/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Scheduling reconnect because error during doReadFromRadio - disconnecting, Bluetooth status=7 while doing readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-23 16:52:49.108 6478-6546/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Forcing disconnect and hopefully device will comeback (disabling forced refresh) +2020-07-23 16:52:49.108 6478-6546/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Closing our GATT connection + - restart advertising after client disconnects (confirm this works if client goes out of range) - started RPA long test, jul 22 6pm - implement nimble software update api -- implement nimble battery level service -- implement device info service remaining fields (hw version etc) * update protocol description per cyclomies email thread * update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2 @@ -34,6 +130,8 @@ Items to complete before 1.0. Items after the first final candidate release. +- implement nimble battery level service +- Nimble implement device info service remaining fields (hw version etc) - Turn on RPA addresses for the device side in Nimble - Try to teardown less of the Nimble protocol stack across sleep - dynamic frequency scaling could save a lot of power on ESP32, but it seems to corrupt uart (even with ref_tick set correctly) diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 5aa073a11..a5f67c0a7 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -26,7 +26,7 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ concurrency::LockGuard g(updateLock); // Check if there is enough to OTA Update - chr_readwrite32le(&updateExpectedSize, ctxt, arg); + chr_readwrite32le(&updateExpectedSize, ctxt); if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) { updateActualSize = 0; @@ -83,7 +83,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble { concurrency::LockGuard g(updateLock); uint32_t expectedCRC = 0; - chr_readwrite32le(&expectedCRC, ctxt, arg); + chr_readwrite32le(&expectedCRC, ctxt); uint32_t actualCRC = crc.finalize(); DEBUG_MSG("expected CRC %u\n", expectedCRC); @@ -121,7 +121,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble 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, arg); + return chr_readwrite8(&update_result, sizeof(update_result), ctxt); } void bluetoothRebootCheck() diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 3e44c21d1..92f47adfe 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -103,7 +103,7 @@ void NodeDB::resetRadioConfig() crypto->setKey(channelSettings.psk.size, channelSettings.psk.bytes); // temp hack for quicker testing - devicestate.no_save = true; + // devicestate.no_save = true; if (devicestate.no_save) { DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n"); diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 2465c2021..f8bbb4d69 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -28,7 +28,7 @@ class NodeDB NodeInfo *nodes; pb_size_t *numNodes; - int readPointer = 0; + uint32_t readPointer = 0; public: bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 29a7f22d0..dc53ac32e 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -387,7 +387,7 @@ 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. */ -int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg) +int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt) { uint8_t le[4]; @@ -419,7 +419,7 @@ int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg) /** * 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, void *arg) +int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { DEBUG_MSG("BLE reading bytes\n"); diff --git a/src/nimble/BluetoothUtil.h b/src/nimble/BluetoothUtil.h index 7a1c62463..453fadb54 100644 --- a/src/nimble/BluetoothUtil.h +++ b/src/nimble/BluetoothUtil.h @@ -22,9 +22,9 @@ void reinitBluetooth(); * 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. */ -int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg); +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, void *arg); \ No newline at end of file +int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt); \ No newline at end of file diff --git a/src/nimble/NimbleBluetoothAPI.cpp b/src/nimble/NimbleBluetoothAPI.cpp index a093cbf5d..dde9171a3 100644 --- a/src/nimble/NimbleBluetoothAPI.cpp +++ b/src/nimble/NimbleBluetoothAPI.cpp @@ -49,9 +49,11 @@ int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - /// DEBUG_MSG("BLE fromRadio called\n"); size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes); + DEBUG_MSG("BLE fromRadio called omlen=%d, ourlen=%d\n", OS_MBUF_PKTLEN(ctxt->om), + numBytes); // the normal case has omlen 1 here + // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue // or make empty if the queue is empty auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes); @@ -62,5 +64,5 @@ int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - return chr_readwrite32le(&fromNum, ctxt, arg); + return chr_readwrite32le(&fromNum, ctxt); } From 204f2c1a68c77c7381c5c076a033afd4b12f444e Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 24 Jul 2020 11:39:30 -0700 Subject: [PATCH 22/25] software update service now registered with NimBLE --- docs/software/TODO.md | 99 +---------------- docs/software/read-error.txt | 148 ++++++++++++++++++++++++++ platformio.ini | 6 +- src/esp32/BluetoothSoftwareUpdate.cpp | 9 +- src/esp32/BluetoothSoftwareUpdate.h | 2 +- src/nimble/BluetoothUtil.cpp | 2 + 6 files changed, 164 insertions(+), 102 deletions(-) create mode 100644 docs/software/read-error.txt diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 8f32024bf..01212d60b 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,104 +4,7 @@ You probably don't care about this section - skip to the next one. Nimble tasks: -- packets >= 79 bytes (FromRadio) cause INVALID_OFFSET (7) gatt errors to be sent to the app - FIXME - add instrumentation - is MTU setting heppening ever? or only on the first attempt? - client is reading nodeinfos. do we do a second 79 byte read, and that one returns 7 because the length is weong? when the second read should have been 72 bytes? - hmm rebooting did not fix - - disconnecting the app and reconnecting it (on the settings screen) did fix it. So is the android app confused? - is the retry on exception thing not tearing enough down? - - could old reads from a previous session be coming back and messing up new reads? do we need to cancel all pending Jobs? - use reliable writes? < I don't think that is the problem? > - -BLE fromRadio called -getFromRadio, !available -toRadioWriteCb data 0x3ffc3d72, len 4 -Trigger powerFSM 9 -Client wants config, nonce=3494 -Reset nodeinfo read pointer -toRadioWriteCb data 0x3ffc3d72, len 4 -Trigger powerFSM 9 -Client wants config, nonce=3493 -Reset nodeinfo read pointer -BLE fromRadio called -getFromRadio, state=2 -encoding toPhone packet to phone variant=3, 50 bytes -BLE fromRadio called -getFromRadio, state=3 -encoding toPhone packet to phone variant=6, 83 bytes -BLE fromRadio called -getFromRadio, state=4 -Sending nodeinfo: num=0xabdddf38, lastseen=1594754867, id=!2462abdddf38, name=Bob b -encoding toPhone packet to phone variant=4, 67 bytes -BLE fromRadio called -getFromRadio, state=4 -Sending nodeinfo: num=0x28b200b4, lastseen=1595545403, id=!246f28b200b4, name=Unknown 00b4 -encoding toPhone packet to phone variant=4, 79 bytes \*\*\*\* -BLE fromRadio called -getFromRadio, state=4 -Sending nodeinfo: num=0xabf84098, lastseen=1593680756, id=!2462abf84098, name=bx n -encoding toPhone packet to phone variant=4, 72 bytes -BLE fromRadio called -getFromRadio, state=4 -Sending nodeinfo: num=0x83f0d8e5, lastseen=1594686931, id=!e8e383f0d8e5, name=Unknown d8e5 -encoding toPhone packet to phone variant=4, 64 bytes -BLE fromRadio called -getFromRadio, state=4 -Done sending nodeinfos -getFromRadio, state=5 - -2020-07-23 16:52:47.843 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.RadioInterfaceService: Broadcasting connection=true -2020-07-23 16:52:47.845 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:47.845 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:47.846 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED -2020-07-23 16:52:47.847 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED -2020-07-23 16:52:47.847 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=4091 -2020-07-23 16:52:47.849 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:47.849 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED -2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED -2020-07-23 16:52:47.852 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=4090 -2020-07-23 16:52:47.852 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: device sleep timeout cancelled -2020-07-23 16:52:47.853 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:47.853 6478-16336/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:48.294 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:48.296 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@1717693 -2020-07-23 16:52:48.296 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 79 bytes from radio -2020-07-23 16:52:48.299 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:48.300 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO -2020-07-23 16:52:48.301 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) -2020-07-23 16:52:48.301 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO -2020-07-23 16:52:48.302 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) -2020-07-23 16:52:48.384 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth\$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -... -07-23 16:52:48.302 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) -2020-07-23 16:52:48.384 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed -2020-07-23 16:52:48.387 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:48.474 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:48.476 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@82276d0 -2020-07-23 16:52:48.476 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed -2020-07-23 16:52:48.833 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:48.835 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@1717693 -2020-07-23 16:52:48.835 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 79 bytes from radio -2020-07-23 16:52:48.837 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:48.839 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO -2020-07-23 16:52:48.840 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) -2020-07-23 16:52:48.840 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO -2020-07-23 16:52:48.842 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=79 (exception Protocol message had invalid UTF-8.) -2020-07-23 16:52:49.104 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:49.106 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=7, res=android.bluetooth.BluetoothGattCharacteristic@1717693 -2020-07-23 16:52:49.107 6478-27868/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Scheduling reconnect because error during doReadFromRadio - disconnecting, Bluetooth status=7 while doing readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 -2020-07-23 16:52:49.108 6478-6546/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Forcing disconnect and hopefully device will comeback (disabling forced refresh) -2020-07-23 16:52:49.108 6478-6546/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Closing our GATT connection - +- readerror.txt - restart advertising after client disconnects (confirm this works if client goes out of range) - started RPA long test, jul 22 6pm - implement nimble software update api diff --git a/docs/software/read-error.txt b/docs/software/read-error.txt new file mode 100644 index 000000000..bb060c0bf --- /dev/null +++ b/docs/software/read-error.txt @@ -0,0 +1,148 @@ +nimble stress test error (private notes for @geeksville) + +findings: +only happens when stress testing multiple sleepwake cycles? +failed packets all have initial mbuflen of zero (should be 1) +restarting the connection on phone sometimes (but not always) fixes it (is the larger config nonce pushing packet size up too large?) +- packets >= 79 bytes (FromRadio) cause INVALID_OFFSET (7) gatt errors to be sent to the app +- some packets are missing + +theory: +some sort of leak in mbuf storage during unfortunately timed sleep shutdowns + + +device side + + +connection updated; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=00:24:62:ab:dd:df + our_id_addr_type=0 our_id_addr=00:24:62:ab:dd:df + peer_ota_addr_type=0 peer_ota_addr=00:7c:d9:5c:ba:2e + peer_id_addr_type=0 peer_id_addr=00:7c:d9:5c:ba:2e + conn_itvl=36 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1 + +BLE fromRadio called +getFromRadio, !available +toRadioWriteCb data 0x3ffc3d72, len 4 +Trigger powerFSM 9 +Transition powerFSM transition=Contact from phone, from=DARK to=DARK +Client wants config, nonce=6864 +Reset nodeinfo read pointer +toRadioWriteCb data 0x3ffc3d72, len 4 +Trigger powerFSM 9 +Transition powerFSM transition=Contact from phone, from=DARK to=DARK +Client wants config, nonce=6863 +Reset nodeinfo read pointer +BLE fromRadio called +getFromRadio, state=2 +encoding toPhone packet to phone variant=3, 50 bytes +BLE fromRadio called +getFromRadio, state=3 +encoding toPhone packet to phone variant=6, 83 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xabdddf38, lastseen=1595606850, id=!2462abdddf38, name=Bob b +encoding toPhone packet to phone variant=4, 67 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0x28b200b4, lastseen=1595606804, id=!246f28b200b4, name=Unknown 00b4 +encoding toPhone packet to phone variant=4, 80 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xabf84098, lastseen=1593680756, id=!2462abf84098, name=bx n +encoding toPhone packet to phone variant=4, 72 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0x83f0d8e5, lastseen=1594686931, id=!e8e383f0d8e5, name=Unknown d8e5 +encoding toPhone packet to phone variant=4, 64 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xd1dc7764, lastseen=1595602082, id=!f008d1dc7764, name=dg +encoding toPhone packet to phone variant=4, 52 bytes +BLE fromRadio called +getFromRadio, state=4 +Sending nodeinfo: num=0xd1dc7828, lastseen=1595598298, id=!f008d1dc7828, name=ryan +encoding toPhone packet to phone variant=4, 54 bytes +BLE fromRadio called +getFromRadio, state=4 +Done sending nodeinfos +getFromRadio, state=5 + + + +phone side + +2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Attempting reconnect +2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: connect +2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: connect +2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: connect() - device: 24:62:AB:DD:DF:3A, auto: false +2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: registerApp() +2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: registerApp() - UUID=026baf7f-d2de-43f1-961f-4e00e04c6fbb +2020-07-24 09:11:00.645 6478-27868/com.geeksville.mesh D/BluetoothGatt: onClientRegistered() - status=0 clientIf=4 +2020-07-24 09:11:01.022 6478-27868/com.geeksville.mesh D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=4 device=24:62:AB:DD:DF:3A +2020-07-24 09:11:01.022 6478-27868/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: new bluetooth connection state 2, status 0 +2020-07-24 09:11:01.023 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work connect is completed, resuming status=0, res=kotlin.Unit +2020-07-24 09:11:01.023 6478-6545/com.geeksville.mesh I/com.geeksville.mesh.service.BluetoothInterface: Connected to radio! +2020-07-24 09:11:01.023 6478-6545/com.geeksville.mesh D/BluetoothGatt: refresh() - device: 24:62:AB:DD:DF:3A +2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: discover +2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: discover +2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/BluetoothGatt: discoverServices() - device: 24:62:AB:DD:DF:3A +2020-07-24 09:11:01.829 6478-27868/com.geeksville.mesh D/BluetoothGatt: onConnectionUpdated() - Device=24:62:AB:DD:DF:3A interval=6 latency=0 timeout=500 status=0 +2020-07-24 09:11:02.008 6478-27868/com.geeksville.mesh D/BluetoothGatt: onSearchComplete() = Device=24:62:AB:DD:DF:3A Status=0 +2020-07-24 09:11:02.009 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work discover is completed, resuming status=0, res=kotlin.Unit +2020-07-24 09:11:02.009 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Discovered services! +2020-07-24 09:11:02.095 6478-27868/com.geeksville.mesh D/BluetoothGatt: onConnectionUpdated() - Device=24:62:AB:DD:DF:3A interval=36 latency=0 timeout=500 status=0 +2020-07-24 09:11:03.010 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.RadioInterfaceService: Broadcasting connection=true +2020-07-24 09:11:03.012 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.012 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED +2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED +2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=6878 +2020-07-24 09:11:03.013 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 *** sending start config +2020-07-24 09:11:03.013 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED +2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED +2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=6877 +2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: device sleep timeout cancelled +2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-24 09:11:03.130 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315 +2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Done reading from radio, fromradio is empty +2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: starting setNotify(ed9da18c-a800-4f66-a670-aa7547e34453, true) *** start notify +2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/BluetoothGatt: setCharacteristicNotification() - uuid: ed9da18c-a800-4f66-a670-aa7547e34453 enable: true +2020-07-24 09:11:03.133 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeD +2020-07-24 09:11:03.220 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7 +2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@2d2062a +2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed +2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.310 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeD +2020-07-24 09:11:03.311 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@2d2062a +2020-07-24 09:11:03.311 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed +2020-07-24 09:11:03.400 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.402 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeD is completed, resuming status=0, res=android.bluetooth.BluetoothGattDescriptor@fc99c1b +2020-07-24 09:11:03.402 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Notify enable=true completed +2020-07-24 09:11:03.769 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315 +2020-07-24 09:11:03.769 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 80 bytes from radio **** received an 80 byte fromradio. Why did we miss three previous reads? +2020-07-24 09:11:03.774 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.774 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:03.774 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=80 (exception Protocol message had invalid UTF-8.) +2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=80 (exception Protocol message had invalid UTF-8.) +2020-07-24 09:11:04.031 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315 +2020-07-24 09:11:04.031 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 52 bytes from radio *** received 52 bytes - where did the previous two read results go? +2020-07-24 09:11:04.033 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:04.033 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:04.034 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-24 09:11:04.035 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=52 (exception While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.) +2020-07-24 09:11:04.036 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO +2020-07-24 09:11:04.036 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=52 (exception While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.) +2020-07-24 09:11:04.210 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=7, res=android.bluetooth.BluetoothGattCharacteristic@556a315 *** read failed +2020-07-24 09:11:04.211 6478-19966/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Scheduling reconnect because error during doReadFromRadio - disconnecting, Bluetooth status=7 while doing readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 +2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Forcing disconnect and hopefully device will comeback (disabling forced refresh) +2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Closing our GATT connection +2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh D/BluetoothGatt: cancelOpen() - device: 24:62:AB:DD:DF:3A +2020-07-24 09:11:04.214 6478-19966/com.geeksville.mesh D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=4 device=24:62:AB:DD:DF:3A +2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: new bluetooth connection state 0, status 0 +2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Got disconnect because we are shutting down, closing gatt +2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh D/BluetoothGatt: close() diff --git a/platformio.ini b/platformio.ini index 600c30b25..12fd78cbd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -155,10 +155,12 @@ debug_tool = jlink build_type = debug ; I'm debugging with ICE a lot now ; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME) build_flags = - ${env.build_flags} -Wno-unused-variable -Isrc/nrf52 -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 + ${env.build_flags} -Wno-unused-variable + -Isrc/nrf52 + -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 ;-DCFG_DEBUG=3 src_filter = - ${env.src_filter} - + ${env.src_filter} - - lib_ignore = BluetoothOTA monitor_port = /dev/ttyACM1 diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index a5f67c0a7..ea1a50ef4 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -136,8 +136,15 @@ void bluetoothRebootCheck() See bluetooth-api.md */ -void createUpdateService() +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); } diff --git a/src/esp32/BluetoothSoftwareUpdate.h b/src/esp32/BluetoothSoftwareUpdate.h index 1efec3d11..c7a412d69 100644 --- a/src/esp32/BluetoothSoftwareUpdate.h +++ b/src/esp32/BluetoothSoftwareUpdate.h @@ -2,7 +2,7 @@ #include "nimble/NimbleDefs.h" -void createUpdateService(); +void reinitUpdateService(); void bluetoothRebootCheck(); diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index dc53ac32e..a1427685e 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -489,6 +489,8 @@ void reinitBluetooth() res = ble_gatts_add_svcs(gatt_svr_svcs); assert(res == 0); + reinitUpdateService(); + /* Set the default device name. */ res = ble_svc_gap_device_name_set(getDeviceName()); assert(res == 0); From 5bab16636d9e725cdeaf0cfd1900b212c5bd378f Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 24 Jul 2020 12:39:35 -0700 Subject: [PATCH 23/25] Switch to NimBLE from Bluedroid Meshtastic patched version esp-idf commit #e7f316d5a4eb64ca52d40575cb20815d456a9c4f used. In support of: https://github.com/meshtastic/Meshtastic-device/issues/266 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 12fd78cbd..be9fcc5cf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -84,7 +84,7 @@ build_flags = # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt platform_packages = - framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#b7f106cd11a04573b902228ea97025c8b5814dd9 + framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#1adba3f11ca8406ac0a704d151697b572058b53d ; not needed included in ttgo-t-beam board file ; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram From d5c46dc114fb7c1c6ef7932d2772080aa0a07c70 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 24 Jul 2020 12:39:48 -0700 Subject: [PATCH 24/25] use max mtusize for speed --- src/nimble/BluetoothUtil.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index a1427685e..efc378d03 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -461,6 +461,8 @@ void reinitBluetooth() nimble_port_init(); + ble_att_set_preferred_mtu(512); + res = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers assert(res == ESP_OK); From 1aa7451866ad6c614534ab9ade5a9d05913afaf0 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 24 Jul 2020 12:41:14 -0700 Subject: [PATCH 25/25] 0.9.1 --- bin/version.sh | 2 +- docs/software/TODO.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/version.sh b/bin/version.sh index 836fd5aa1..bf6adf67a 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=0.8.2 \ No newline at end of file +export VERSION=0.9.1 \ No newline at end of file diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 01212d60b..4a63cf040 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,10 +4,11 @@ You probably don't care about this section - skip to the next one. Nimble tasks: -- readerror.txt -- restart advertising after client disconnects (confirm this works if client goes out of range) +- readerror.txt stress test bug - started RPA long test, jul 22 6pm - implement nimble software update api +- update to latest bins, test OTA again (measure times) and then checkin bins +- do alpha release * update protocol description per cyclomies email thread * update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2