From 80e8b4adcc8d6d69e97ebe34df35c37c4f4a4f82 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 14:19:38 -0700 Subject: [PATCH 01/17] turn off gps debug output for now RAK815 --- src/gps/UBloxGPS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 8c3d7dd20..142e416f2 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -42,7 +42,7 @@ bool UBloxGPS::setup() delay(200); // Give time for the GPS to startup after we gave power #endif - ublox.enableDebugging(Serial); + // ublox.enableDebugging(Serial); // try a second time, the ublox lib serial parsing is buggy? if (!tryConnect()) From e46bebc06f2dfff4e0e39d4bfd0e3f17fd62ac3c Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 14:19:23 -0700 Subject: [PATCH 02/17] rename docs --- docs/software/{bluetooth-api.md => device-api.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/software/{bluetooth-api.md => device-api.md} (100%) diff --git a/docs/software/bluetooth-api.md b/docs/software/device-api.md similarity index 100% rename from docs/software/bluetooth-api.md rename to docs/software/device-api.md From 2ff94cb11d6eed704b92de9b4e150964679624f5 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 14:41:04 -0700 Subject: [PATCH 03/17] Update device protocol docs --- docs/software/device-api.md | 40 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/software/device-api.md b/docs/software/device-api.md index 78bcb6539..30a43213d 100644 --- a/docs/software/device-api.md +++ b/docs/software/device-api.md @@ -1,12 +1,26 @@ -# Bluetooth API +# Device API -The Bluetooth API is design to have only a few characteristics and most polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone. +The Device API is design to have only a simple stream of ToRadio and FromRadio packets and all polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone. -## A note on MTU sizes +## Streaming version -This device will work with any MTU size, but it is highly recommended that you call your phone's "setMTU function to increase MTU to 512 bytes" as soon as you connect to a service. This will dramatically improve performance when reading/writing packets. +This protocol is **almost** identical when it is deployed over BLE, Serial/USB or TCP (our three currently supported transports for connecting to phone/PC). Most of this document is in terms of the original BLE version, but this section describes the small changes when this API is exposed over a Streaming (non datagram) transport. The streaming version has the following changes: -## MeshBluetoothService +- We assume the stream is reliable (though the protocol will resynchronize if bytes are lost or corrupted). i.e. we do not include CRCs or error correction codes. +- Packets always have a four byte header (described below) prefixed before each packet. This header provides framing characters and length. +- The stream going towards the radio is only a series of ToRadio packets (with the extra 4 byte headers) +- The stream going towards the PC is a stream of FromRadio packets (with the 4 byte headers), or if the receiver state machine does not see valid header bytes it can (optionally) print those bytes as the debug console from the radio. This allows the device to emit regular serial debugging messages (which can be understood by a terminal program) but also switch to a more structured set of protobufs once it sees that the PC client has sent a protobuf towards it. + +The 4 byte header is constructed to both provide framing and to not look line 'normal' 7 bit ASCII. + +- Byte 0: START1 (0x94) +- Byte 1: START2 (0xc3) +- Byte 2: MSB of protobuf length +- Byte 3: LSB of protobuf length + +The receiver will validate length and if >512 it will assume the packet is corrupted and return to looking for START1. While looking for START1 any other characters are printed as "debug output". For small example implementation of this reader see the meshtastic-python implementation. + +## MeshBluetoothService (the BLE API) This is the main bluetooth service for the device and provides the API your app should use to get information about the mesh, send packets or provision the radio. @@ -71,16 +85,20 @@ Not all messages are kept in the fromradio queue (filtered based on SubPacket): - No WantNodeNum / DenyNodeNum messages are kept A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging) -## Protobuf API +### A note on MTU sizes + +This device will work with any MTU size, but it is highly recommended that you call your phone's "setMTU function to increase MTU to 512 bytes" as soon as you connect to a service. This will dramatically improve performance when reading/writing packets. + +### Protobuf API On connect, you should send a want_config_id protobuf to the device. This will cause the device to send its node DB and radio config via the fromradio endpoint. After sending the full DB, the radio will send a want_config_id to indicate it is done sending the configuration. -## Other bluetooth services +### Other bluetooth services -This document focuses on the core mesh service, but it is worth noting that the following other Bluetooth services are also +This document focuses on the core device protocol, but it is worth noting that the following other Bluetooth services are also provided by the device. -### BluetoothSoftwareUpdate +#### BluetoothSoftwareUpdate The software update service. For a sample function that performs a software update using this API see [startUpdate](https://github.com/meshtastic/Meshtastic-Android/blob/master/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt). @@ -98,10 +116,10 @@ Characteristics | GATT_UUID_MANU_NAME/0x2a29 | read | | | GATT_UUID_HW_VERSION_STR/0x2a27 | read | | -### DeviceInformationService +#### DeviceInformationService Implements the standard BLE contract for this service (has software version, hardware model, serial number, etc...) -### BatteryLevelService +#### BatteryLevelService Implements the standard BLE contract service, provides battery level in a way that most client devices should automatically understand (i.e. it should show in the bluetooth devices screen automatically) From 55673fcd667a8fb789a55a2fb2dc39f6be67685a Mon Sep 17 00:00:00 2001 From: Rezl Date: Mon, 13 Jul 2020 19:34:14 -0500 Subject: [PATCH 04/17] Added Beginner's Guide --- docs/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/README.md b/docs/README.md index f6cbf4fef..9e3b24d0a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,9 @@ This project is currently in beta testing but it is fairly stable and feature co This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [forum](https://meshtastic.discourse.group/). +### Beginner's Guide +For an inclusive walkthrough aimed at beginners, we reccomend: https://meshtastic.letstalkthis.com/ + # Updates Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum. From d9209ffaea675bba7c5e23101ff142bcb8735784 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 17:47:22 -0700 Subject: [PATCH 05/17] fix doc typo --- docs/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 9e3b24d0a..7017a42b9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -36,7 +36,8 @@ This project is currently in beta testing but it is fairly stable and feature co This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [forum](https://meshtastic.discourse.group/). ### Beginner's Guide -For an inclusive walkthrough aimed at beginners, we reccomend: https://meshtastic.letstalkthis.com/ + +For an detailed walkthrough aimed at beginners, we recommend: https://meshtastic.letstalkthis.com/ # Updates From c7213fb7101d473f4aff55160dfc5be9ad699cca Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 17:54:12 -0700 Subject: [PATCH 06/17] Fix URL --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 7017a42b9..0db68fa41 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,7 +37,7 @@ This software is 100% open source and developed by a group of hobbyist experimen ### Beginner's Guide -For an detailed walkthrough aimed at beginners, we recommend: https://meshtastic.letstalkthis.com/ +For an detailed walk-through aimed at beginners, we recommend [meshtastic.letstalkthis.com](https://meshtastic.letstalkthis.com/) # Updates From da3b6d1958a80d7250da1e893194ce07101cf7cd Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 13 Jul 2020 17:55:30 -0700 Subject: [PATCH 07/17] Fix URL --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 7017a42b9..c39234bed 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,7 +37,7 @@ This software is 100% open source and developed by a group of hobbyist experimen ### Beginner's Guide -For an detailed walkthrough aimed at beginners, we recommend: https://meshtastic.letstalkthis.com/ +For an detailed walk-through aimed at beginners, we recommend [meshtastic.letstalkthis.com](https://meshtastic.letstalkthis.com/). # Updates From 4147786b12e13baaee04ab8936942f16d3aadc3b Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 15 Jul 2020 13:10:56 -0700 Subject: [PATCH 08/17] WIP of adding NRF52 bluetooth API, we take a hardfault in Bluefruit init --- src/BluetoothCommon.h | 14 +++ src/esp32/MeshBluetoothService.cpp | 22 ++-- src/nrf52/NRF52Bluetooth.cpp | 176 ++++++++++++++++------------- src/nrf52/main-nrf52.cpp | 6 +- 4 files changed, 123 insertions(+), 95 deletions(-) diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 5d551d079..14be8a916 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -1,8 +1,22 @@ #pragma once +#include + /** * Common lib functions for all platforms that have bluetooth */ +#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd" + +#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" +#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5" +#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" + +// NRF52 wants these constants without the hypen and I'm lazy +#define MESH_SERVICE_UUID_16 ((const uint8_t *)"6ba1b21815a8461f9fa85dcae273eafd") +#define TORADIO_UUID_16 ((const uint8_t *)"f75c76d2129e4dada1dd7866124401e7") +#define FROMRADIO_UUID_16 ((const uint8_t *)"8ba2bcc2ee024a55a531c525c5e454d5") +#define FROMNUM_UUID_16 ((const uint8_t *)"ed9da18ca8004f66a670aa7547e34453") + /// 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/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp index 9bc41459a..044bbc4e4 100644 --- a/src/esp32/MeshBluetoothService.cpp +++ b/src/esp32/MeshBluetoothService.cpp @@ -5,6 +5,7 @@ #include #include +#include "BluetoothCommon.h" #include "CallbackCharacteristic.h" #include "GPS.h" #include "MeshService.h" @@ -39,26 +40,20 @@ class BluetoothPhoneAPI : public PhoneAPI } }; -BluetoothPhoneAPI *bluetoothPhoneAPI; - +static BluetoothPhoneAPI *bluetoothPhoneAPI; class ToRadioCharacteristic : public CallbackCharacteristic { public: - ToRadioCharacteristic() : CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE) {} + ToRadioCharacteristic() : CallbackCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE) {} - void onWrite(BLECharacteristic *c) - { - bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length()); - } + void onWrite(BLECharacteristic *c) { bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length()); } }; class FromRadioCharacteristic : public CallbackCharacteristic { public: - FromRadioCharacteristic() : CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ) - { - } + FromRadioCharacteristic() : CallbackCharacteristic(FROMRADIO_UUID, BLECharacteristic::PROPERTY_READ) {} void onRead(BLECharacteristic *c) { @@ -78,9 +73,8 @@ class FromNumCharacteristic : public CallbackCharacteristic { public: FromNumCharacteristic() - : CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453", BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_NOTIFY) + : CallbackCharacteristic(FROMNUM_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_NOTIFY) { // observe(&service.fromNumChanged); } @@ -100,7 +94,7 @@ BLEService *createMeshBluetoothService(BLEServer *server) } // Create the BLE Service, we need more than the default of 15 handles - BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 30, 0); + BLEService *service = server->createService(BLEUUID(MESH_SERVICE_UUID), 30, 0); assert(!meshFromNumCharacteristic); meshFromNumCharacteristic = new FromNumCharacteristic; diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 03e5b8909..ed1f39d2e 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -1,23 +1,38 @@ #include "NRF52Bluetooth.h" +#include "BluetoothCommon.h" #include "configuration.h" #include "main.h" -#include "BluetoothCommon.h" #include -/* HRM Service Definitions - * Heart Rate Monitor Service: 0x180D - * Heart Rate Measurement Char: 0x2A37 - * Body Sensor Location Char: 0x2A38 - */ -BLEService hrms = BLEService(UUID16_SVC_HEART_RATE); -BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT); -BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION); +static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); +static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); +static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); +static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); -BLEDis bledis; // DIS (Device Information Service) helper class instance -BLEBas blebas; // BAS (Battery Service) helper class instance -BLEDfu bledfu; // DFU software update helper service +static BLEDis bledis; // DIS (Device Information Service) helper class instance +static BLEBas blebas; // BAS (Battery Service) helper class instance +static BLEDfu bledfu; // DFU software update helper service -uint8_t bps = 0; +// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in +// proccess at once +// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; +static uint8_t fromRadioBytes[FromRadio_size]; + +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; void connect_callback(uint16_t conn_handle) { @@ -27,7 +42,7 @@ void connect_callback(uint16_t conn_handle) char central_name[32] = {0}; connection->getPeerName(central_name, sizeof(central_name)); - DEBUG_MSG("Connected to %s\n", central_name); + DEBUG_MSG("BLE Connected to %s\n", central_name); } /** @@ -38,9 +53,8 @@ void connect_callback(uint16_t conn_handle) void disconnect_callback(uint16_t conn_handle, uint8_t reason) { (void)conn_handle; - (void)reason; - DEBUG_MSG("Disconnected, reason = 0x%x\n", reason); + DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason); } void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) @@ -50,11 +64,11 @@ void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_valu // Check the characteristic this CCCD update is associated with in case // this handler is used for multiple CCCD records. - if (chr->uuid == hrmc.uuid) { + if (chr->uuid == fromNum.uuid) { if (chr->notifyEnabled(conn_hdl)) { - DEBUG_MSG("Heart Rate Measurement 'Notify' enabled\n"); + DEBUG_MSG("fromNum 'Notify' enabled\n"); } else { - DEBUG_MSG("Heart Rate Measurement 'Notify' disabled\n"); + DEBUG_MSG("fromNum 'Notify' disabled\n"); } } } @@ -66,7 +80,7 @@ void startAdv(void) Bluefruit.Advertising.addTxPower(); // Include HRM Service UUID - Bluefruit.Advertising.addService(hrms); + Bluefruit.Advertising.addService(meshBleService); // Include Name Bluefruit.Advertising.addName(); @@ -86,67 +100,72 @@ void startAdv(void) Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds } -void setupHRM(void) +/** + * client is starting read, pull the bytes from our API class + */ +void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) { - // Configure the Heart Rate Monitor service - // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml - // Supported Characteristics: - // Name UUID Requirement Properties - // ---------------------------- ------ ----------- ---------- - // Heart Rate Measurement 0x2A37 Mandatory Notify - // Body Sensor Location 0x2A38 Optional Read - // Heart Rate Control Point 0x2A39 Conditional Write <-- Not used here - hrms.begin(); + size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); + + DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes); + + // 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 + chr->write(fromRadioBytes, numBytes); +} + +void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) +{ + DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len); + + bluetoothPhoneAPI->handleToRadio(data, len); +} + +/** + * client is starting read, pull the bytes from our API class + */ +void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) +{ + DEBUG_MSG("fromNumAuthorizeCb FIXME - implement\n"); +} + +void setupMeshService(void) +{ + bluetoothPhoneAPI = new BluetoothPhoneAPI(); + bluetoothPhoneAPI->init(); + + meshBleService.begin(); // Note: You must call .begin() on the BLEService before calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on // a BLECharacteristic will cause it to be added to the last BLEService that // was 'begin()'ed! - // Configure the Heart Rate Measurement characteristic - // See: - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml - // Properties = Notify - // Min Len = 1 - // Max Len = 8 - // B0 = UINT8 - Flag (MANDATORY) - // b5:7 = Reserved - // b4 = RR-Internal (0 = Not present, 1 = Present) - // b3 = Energy expended status (0 = Not present, 1 = Present) - // b1:2 = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and - // detected) b0 = Value format (0 = UINT8, 1 = UINT16) - // B1 = UINT8 - 8-bit heart rate measurement value in BPM - // B2:3 = UINT16 - 16-bit heart rate measurement value in BPM - // B4:5 = UINT16 - Energy expended in joules - // B6:7 = UINT16 - RR Internal (1/1024 second resolution) - hrmc.setProperties(CHR_PROPS_NOTIFY); - hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); - hrmc.setFixedLen(2); - hrmc.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates - hrmc.begin(); - uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and detected - hrmc.write(hrmdata, 2); + fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); + fromNum.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!! + fromNum.setFixedLen( + 0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty + fromNum.setMaxLen(4); + fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates + fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb); + fromNum.begin(); + // uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and + // detected + // hrmc.write(hrmdata, 2); - // Configure the Body Sensor Location characteristic - // See: - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml - // Properties = Read - // Min Len = 1 - // Max Len = 1 - // B0 = UINT8 - Body Sensor Location - // 0 = Other - // 1 = Chest - // 2 = Wrist - // 3 = Finger - // 4 = Hand - // 5 = Ear Lobe - // 6 = Foot - // 7:255 = Reserved - bslc.setProperties(CHR_PROPS_READ); - bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); - bslc.setFixedLen(1); - bslc.begin(); - bslc.write8(2); // Set the characteristic to 'Wrist' (2) + fromRadio.setProperties(CHR_PROPS_READ); + fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! + fromRadio.setMaxLen(512); + fromRadio.setReadAuthorizeCallback(fromRadioAuthorizeCb); + fromRadio.setBuffer(fromRadioBytes, + sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space for two copies + fromRadio.begin(); + + toRadio.setProperties(CHR_PROPS_WRITE); + toRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! + toRadio.setMaxLen(512); + toRadio.setWriteCallback(toRadioWriteCb); + toRadio.begin(); } // FIXME, turn off soft device access for debugging @@ -174,14 +193,14 @@ void NRF52Bluetooth::setup() // Start the BLE Battery Service and set it to 100% DEBUG_MSG("Configuring the Battery Service\n"); blebas.begin(); - blebas.write(42); // FIXME, report real power levels + blebas.write(0); // Unknown battery level for now bledfu.begin(); // Install the DFU helper // Setup the Heart Rate Monitor service using // BLEService and BLECharacteristic classes - DEBUG_MSG("Configuring the Heart Rate Monitor Service\n"); - setupHRM(); + DEBUG_MSG("Configuring the Mesh bluetooth service\n"); + setupMeshService(); // Supposedly debugging works with soft device if you disable advertising if (isSoftDeviceAllowed) { @@ -194,8 +213,9 @@ void NRF52Bluetooth::setup() } /// Given a level between 0-100, update the BLE attribute -void updateBatteryLevel(uint8_t level) { - // FIXME - implement +void updateBatteryLevel(uint8_t level) +{ + blebas.write(level); } /* diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index 9f81f074c..d2fd1e060 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -52,9 +52,9 @@ void setBluetoothEnable(bool on) if (on != bleOn) { if (on) { if (!nrf52Bluetooth) { - DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); - //nrf52Bluetooth = new NRF52Bluetooth(); - //nrf52Bluetooth->setup(); + // DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->setup(); } } else { DEBUG_MSG("FIXME: implement BLE disable\n"); From f919eb6a6466669aef0dd719436f0040d82fe984 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 15 Jul 2020 13:24:57 -0700 Subject: [PATCH 09/17] Install a hardfault handler on NRF52 --- src/configuration.h | 9 ++++-- src/nrf52/NRF52Bluetooth.cpp | 56 +----------------------------------- src/nrf52/hardfault.cpp | 52 +++++++++++++++++---------------- 3 files changed, 36 insertions(+), 81 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 93490d844..d254b9808 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -305,9 +305,15 @@ along with this program. If not, see . // What platforms should use SEGGER? #ifdef NRF52_SERIES +// Always include the SEGGER code on NRF52 - because useful for debugging +#include "SEGGER_RTT.h" + +// Debug printing to segger console +#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__) + // nrf52 gets its settings via variant files #ifndef PIN_SERIAL_RX -// No serial ports on this board - use segger in memory console +// No serial ports on this board - ONLY use segger in memory console #define USE_SEGGER #endif @@ -316,7 +322,6 @@ along with this program. If not, see . #endif #ifdef USE_SEGGER -#include "SEGGER_RTT.h" #define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__) #else #ifdef DEBUG_PORT diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index ed1f39d2e..8e1790d73 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -216,58 +216,4 @@ void NRF52Bluetooth::setup() void updateBatteryLevel(uint8_t level) { blebas.write(level); -} - -/* -void loop() -{ - digitalToggle(LED_RED); - - if ( Bluefruit.connected() ) { - uint8_t hrmdata[2] = { 0b00000110, bps++ }; // Sensor connected, increment BPS value - - // Note: We use .notify instead of .write! - // If it is connected but CCCD is not enabled - // The characteristic's value is still updated although notification is not sent - if ( hrmc.notify(hrmdata, sizeof(hrmdata)) ){ - Serial.print("Heart Rate Measurement updated to: "); Serial.println(bps); - }else{ - Serial.println("ERROR: Notify not set in the CCCD or not connected!"); - } - } - - // Only send update once per second - delay(1000); -} -*/ - -/* -examples of advanced characteristics. use setReadAuthorizeCallback to prepare data for reads by others - -err_t BLEDfu::begin(void) -{ - // Invoke base class begin() - VERIFY_STATUS( BLEService::begin() ); - - // No need to keep packet & revision characteristics - BLECharacteristic chr_packet(UUID128_CHR_DFU_PACKET); - chr_packet.setTempMemory(); - chr_packet.setProperties(CHR_PROPS_WRITE_WO_RESP); - chr_packet.setMaxLen(20); - VERIFY_STATUS( chr_packet.begin() ); - - _chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_NOTIFY); - _chr_control.setMaxLen(23); - _chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb); - VERIFY_STATUS( _chr_control.begin() ); - - BLECharacteristic chr_revision(UUID128_CHR_DFU_REVISON); - chr_revision.setTempMemory(); - chr_revision.setProperties(CHR_PROPS_READ); - chr_revision.setFixedLen(2); - VERIFY_STATUS( chr_revision.begin()); - chr_revision.write16(DFU_REV_APPMODE); - - return ERROR_NONE; -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/nrf52/hardfault.cpp b/src/nrf52/hardfault.cpp index 4cf4dff79..f49bba688 100644 --- a/src/nrf52/hardfault.cpp +++ b/src/nrf52/hardfault.cpp @@ -5,47 +5,51 @@ enum { r0, r1, r2, r3, r12, lr, pc, psr }; +// we can't use the regular DEBUG_MSG for these crash dumps because it depends on threading still being running. Instead use the +// segger in memory tool +#define FAULT_MSG(...) SEGGER_MSG(__VA_ARGS__) + // Per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html static void printUsageErrorMsg(uint32_t cfsr) { - DEBUG_MSG("Usage fault: "); + FAULT_MSG("Usage fault: "); cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb if ((cfsr & (1 << 9)) != 0) - DEBUG_MSG("Divide by zero\n"); + FAULT_MSG("Divide by zero\n"); if ((cfsr & (1 << 8)) != 0) - DEBUG_MSG("Unaligned\n"); + FAULT_MSG("Unaligned\n"); } static void printBusErrorMsg(uint32_t cfsr) { - DEBUG_MSG("Usage fault: "); + FAULT_MSG("Bus fault: "); cfsr >>= SCB_CFSR_BUSFAULTSR_Pos; // right shift to lsb if ((cfsr & (1 << 0)) != 0) - DEBUG_MSG("Instruction bus error\n"); + FAULT_MSG("Instruction bus error\n"); if ((cfsr & (1 << 1)) != 0) - DEBUG_MSG("Precise data bus error\n"); + FAULT_MSG("Precise data bus error\n"); if ((cfsr & (1 << 2)) != 0) - DEBUG_MSG("Imprecise data bus error\n"); + FAULT_MSG("Imprecise data bus error\n"); } static void printMemErrorMsg(uint32_t cfsr) { - DEBUG_MSG("Usage fault: "); + FAULT_MSG("Memory fault: "); cfsr >>= SCB_CFSR_MEMFAULTSR_Pos; // right shift to lsb if ((cfsr & (1 << 0)) != 0) - DEBUG_MSG("Instruction access violation\n"); + FAULT_MSG("Instruction access violation\n"); if ((cfsr & (1 << 1)) != 0) - DEBUG_MSG("Data access violation\n"); + FAULT_MSG("Data access violation\n"); } -static void HardFault_Impl(uint32_t stack[]) +extern "C" void HardFault_Impl(uint32_t stack[]) { - DEBUG_MSG("In Hard Fault Handler\n"); - DEBUG_MSG("SCB->HFSR = 0x%08lx\n", SCB->HFSR); + FAULT_MSG("In Hard Fault Handler\n"); + FAULT_MSG("SCB->HFSR = 0x%08lx\n", SCB->HFSR); if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) { - DEBUG_MSG("Forced Hard Fault\n"); - DEBUG_MSG("SCB->CFSR = 0x%08lx\n", SCB->CFSR); + FAULT_MSG("Forced Hard Fault\n"); + FAULT_MSG("SCB->CFSR = 0x%08lx\n", SCB->CFSR); if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) { printUsageErrorMsg(SCB->CFSR); @@ -57,21 +61,21 @@ static void HardFault_Impl(uint32_t stack[]) printMemErrorMsg(SCB->CFSR); } - DEBUG_MSG("r0 = 0x%08lx\n", stack[r0]); - DEBUG_MSG("r1 = 0x%08lx\n", stack[r1]); - DEBUG_MSG("r2 = 0x%08lx\n", stack[r2]); - DEBUG_MSG("r3 = 0x%08lx\n", stack[r3]); - DEBUG_MSG("r12 = 0x%08lx\n", stack[r12]); - DEBUG_MSG("lr = 0x%08lx\n", stack[lr]); - DEBUG_MSG("pc = 0x%08lx\n", stack[pc]); - DEBUG_MSG("psr = 0x%08lx\n", stack[psr]); + FAULT_MSG("r0 = 0x%08lx\n", stack[r0]); + FAULT_MSG("r1 = 0x%08lx\n", stack[r1]); + FAULT_MSG("r2 = 0x%08lx\n", stack[r2]); + FAULT_MSG("r3 = 0x%08lx\n", stack[r3]); + FAULT_MSG("r12 = 0x%08lx\n", stack[r12]); + FAULT_MSG("lr = 0x%08lx\n", stack[lr]); + FAULT_MSG("pc = 0x%08lx\n", stack[pc]); + FAULT_MSG("psr = 0x%08lx\n", stack[psr]); asm volatile("bkpt #01"); while (1) ; } } -void HardFault_Handler(void) +extern "C" void HardFault_Handler(void) { asm volatile(" mrs r0,msp\n" " b HardFault_Impl \n"); From 6cb92143ecc78b34f6d4c959dfc5aa2d1cdb8294 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 15 Jul 2020 13:45:57 -0700 Subject: [PATCH 10/17] OOM allocing the BLE stack for adafruit --- docs/software/nrf52-TODO.md | 1 + src/nrf52/hardfault.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index f95e93d4b..eaacdb7ac 100644 --- a/docs/software/nrf52-TODO.md +++ b/docs/software/nrf52-TODO.md @@ -5,6 +5,7 @@ TODO: - i2c gps comms not quite right +- ble: AdafruitBluefruit::begin - adafruit_ble_task was assigned an invalid stack pointer. out of memory? - measure power draw ### Bootloader diff --git a/src/nrf52/hardfault.cpp b/src/nrf52/hardfault.cpp index f49bba688..67180c833 100644 --- a/src/nrf52/hardfault.cpp +++ b/src/nrf52/hardfault.cpp @@ -44,12 +44,10 @@ static void printMemErrorMsg(uint32_t cfsr) extern "C" void HardFault_Impl(uint32_t stack[]) { - FAULT_MSG("In Hard Fault Handler\n"); - FAULT_MSG("SCB->HFSR = 0x%08lx\n", SCB->HFSR); + FAULT_MSG("Hard Fault occurred! SCB->HFSR = 0x%08lx\n", SCB->HFSR); if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) { - FAULT_MSG("Forced Hard Fault\n"); - FAULT_MSG("SCB->CFSR = 0x%08lx\n", SCB->CFSR); + FAULT_MSG("Forced Hard Fault: SCB->CFSR = 0x%08lx\n", SCB->CFSR); if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) { printUsageErrorMsg(SCB->CFSR); @@ -69,10 +67,12 @@ extern "C" void HardFault_Impl(uint32_t stack[]) FAULT_MSG("lr = 0x%08lx\n", stack[lr]); FAULT_MSG("pc = 0x%08lx\n", stack[pc]); FAULT_MSG("psr = 0x%08lx\n", stack[psr]); - asm volatile("bkpt #01"); - while (1) - ; } + + FAULT_MSG("Done with fault report - Waiting to reboot\n"); + asm volatile("bkpt #01"); // Enter the debugger if one is connected + while (1) + ; } extern "C" void HardFault_Handler(void) From 3d0c6118967caf96886a3a1346413801fa6d022b Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 15 Jul 2020 17:09:09 -0700 Subject: [PATCH 11/17] android app can now talk to NRF52, but writes are lost WIP --- src/BluetoothCommon.h | 6 ------ src/nrf52/NRF52Bluetooth.cpp | 31 +++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 14be8a916..61a8fe5ea 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -12,11 +12,5 @@ #define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" -// NRF52 wants these constants without the hypen and I'm lazy -#define MESH_SERVICE_UUID_16 ((const uint8_t *)"6ba1b21815a8461f9fa85dcae273eafd") -#define TORADIO_UUID_16 ((const uint8_t *)"f75c76d2129e4dada1dd7866124401e7") -#define FROMRADIO_UUID_16 ((const uint8_t *)"8ba2bcc2ee024a55a531c525c5e454d5") -#define FROMNUM_UUID_16 ((const uint8_t *)"ed9da18ca8004f66a670aa7547e34453") - /// 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/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 8e1790d73..007113def 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -4,6 +4,17 @@ #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)); static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); @@ -17,6 +28,7 @@ static BLEDfu bledfu; // DFU software update helper service // proccess at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; static uint8_t fromRadioBytes[FromRadio_size]; +static uint8_t toRadioBytes[ToRadio_size]; class BluetoothPhoneAPI : public PhoneAPI { @@ -77,10 +89,10 @@ void startAdv(void) { // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); - // Include HRM Service UUID - Bluefruit.Advertising.addService(meshBleService); + // IncludeService UUID + Bluefruit.ScanResponse.addService(meshBleService); + Bluefruit.ScanResponse.addTxPower(); // Include Name Bluefruit.Advertising.addName(); @@ -97,7 +109,7 @@ void startAdv(void) Bluefruit.Advertising.restartOnDisconnect(true); Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } /** @@ -163,13 +175,15 @@ void setupMeshService(void) toRadio.setProperties(CHR_PROPS_WRITE); toRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! + toRadio.setFixedLen(0); toRadio.setMaxLen(512); + toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); toRadio.setWriteCallback(toRadioWriteCb); toRadio.begin(); } // FIXME, turn off soft device access for debugging -static bool isSoftDeviceAllowed = false; +static bool isSoftDeviceAllowed = true; void NRF52Bluetooth::setup() { @@ -178,7 +192,7 @@ void NRF52Bluetooth::setup() Bluefruit.begin(); // Set the advertised device name (keep it short!) - Bluefruit.setName(getDeviceName()); // FIXME + Bluefruit.setName(getDeviceName()); // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(connect_callback); @@ -186,8 +200,9 @@ void NRF52Bluetooth::setup() // Configure and Start the Device Information Service DEBUG_MSG("Configuring the Device Information Service\n"); - bledis.setManufacturer("meshtastic.org"); - bledis.setModel("NRF52-meshtastic"); // FIXME + bledis.setManufacturer(HW_VENDOR); + bledis.setModel(optstr(HW_VERSION)); + bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.begin(); // Start the BLE Battery Service and set it to 100% From 769a98f1f4c221cbf69c09d57b98560ae7b7b8f6 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 09:13:47 -0700 Subject: [PATCH 12/17] nrf52 ble - move service in into the scan info --- src/nrf52/NRF52Bluetooth.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 007113def..71e213208 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -91,11 +91,13 @@ void startAdv(void) Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); // IncludeService UUID - Bluefruit.ScanResponse.addService(meshBleService); + // Bluefruit.ScanResponse.addService(meshBleService); Bluefruit.ScanResponse.addTxPower(); + Bluefruit.ScanResponse.addName(); // Include Name - Bluefruit.Advertising.addName(); + // Bluefruit.Advertising.addName(); + Bluefruit.Advertising.addService(meshBleService); /* Start Advertising * - Enable auto advertising if disconnected From 5700cf96d55aebaf6fce714d8d2b626ecc19bd6a Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 09:14:23 -0700 Subject: [PATCH 13/17] redefine printf to use the segger output system (NRF52) --- src/nrf52/main-nrf52.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index d2fd1e060..08d2baf00 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef NRF52840_XXAA // #include @@ -63,6 +64,18 @@ void setBluetoothEnable(bool on) } } +/** + * Override printf to use the SEGGER output library + */ +int printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + auto res = SEGGER_RTT_vprintf(0, fmt, &args); + va_end(args); + return res; +} + void nrf52Setup() { @@ -84,4 +97,5 @@ void nrf52Setup() // ble_controller_rand_vector_get_blocking(&r, sizeof(r)); // randomSeed(r); DEBUG_MSG("FIXME, call randomSeed\n"); + // ::printf("TESTING PRINTF\n"); } \ No newline at end of file From 582f77e4eca7693304c97dded4c3bb6efac77fce Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 10:02:07 -0700 Subject: [PATCH 14/17] NRF52 BLE now works, except for reads having the wrong payload --- src/nrf52/NRF52Bluetooth.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 71e213208..175ce404e 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -114,6 +114,14 @@ void startAdv(void) Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } +// Just ack that the caller is allowed to read +static void authorizeRead(uint16_t conn_hdl) +{ + ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ}; + reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); +} + /** * client is starting read, pull the bytes from our API class */ @@ -126,6 +134,7 @@ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e // 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 chr->write(fromRadioBytes, numBytes); + authorizeRead(conn_hdl); } void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) @@ -140,7 +149,9 @@ void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, ui */ void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) { - DEBUG_MSG("fromNumAuthorizeCb FIXME - implement\n"); + DEBUG_MSG("fromNumAuthorizeCb\n"); + + authorizeRead(conn_hdl); } void setupMeshService(void) @@ -161,7 +172,9 @@ void setupMeshService(void) 0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty fromNum.setMaxLen(4); fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates - fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb); + // We don't yet need to hook the fromNum auth callback + // fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb); + fromNum.write32(0); // Provide default fromNum of 0 fromNum.begin(); // uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and // detected @@ -176,7 +189,7 @@ void setupMeshService(void) fromRadio.begin(); toRadio.setProperties(CHR_PROPS_WRITE); - toRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! + toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this! toRadio.setFixedLen(0); toRadio.setMaxLen(512); toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); From 28aa48c8d22fae3cd69a1431344b8490bda6ac4f Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 10:40:03 -0700 Subject: [PATCH 15/17] NRF52 reads now work, but not long reads --- src/nrf52/NRF52Bluetooth.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 175ce404e..1959916c9 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -130,10 +130,12 @@ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes); + if (numBytes >= 2) + DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]); // 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 - chr->write(fromRadioBytes, numBytes); + fromRadio.write(fromRadioBytes, numBytes); authorizeRead(conn_hdl); } @@ -182,10 +184,13 @@ void setupMeshService(void) fromRadio.setProperties(CHR_PROPS_READ); fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! - fromRadio.setMaxLen(512); - fromRadio.setReadAuthorizeCallback(fromRadioAuthorizeCb); - fromRadio.setBuffer(fromRadioBytes, - sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space for two copies + fromRadio.setMaxLen(sizeof(fromRadioBytes)); + fromRadio.setReadAuthorizeCallback( + fromRadioAuthorizeCb, + false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context + // FIXME - add this back in + // fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space + // for two copies fromRadio.begin(); toRadio.setProperties(CHR_PROPS_WRITE); @@ -193,7 +198,9 @@ void setupMeshService(void) toRadio.setFixedLen(0); toRadio.setMaxLen(512); toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); - toRadio.setWriteCallback(toRadioWriteCb); + toRadio.setWriteCallback( + toRadioWriteCb, + false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context toRadio.begin(); } From 2a6df797ca76168332a40c811aa837cc93efccc4 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 11:12:05 -0700 Subject: [PATCH 16/17] NRF52 BLE API now works! --- src/nrf52/NRF52Bluetooth.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 1959916c9..2ae864aae 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -127,15 +127,20 @@ static void authorizeRead(uint16_t conn_hdl) */ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) { - size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); + if (request->offset == 0) { + // If the read is long, we will get multiple authorize invocations - we only populate data on the first - DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes); - if (numBytes >= 2) - DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]); + size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); - // 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 - fromRadio.write(fromRadioBytes, numBytes); + // DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes); + // if (numBytes >= 2) DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]); + + // 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 + fromRadio.write(fromRadioBytes, numBytes); + } else { + // DEBUG_MSG("Ignoring successor read\n"); + } authorizeRead(conn_hdl); } @@ -188,8 +193,7 @@ void setupMeshService(void) fromRadio.setReadAuthorizeCallback( fromRadioAuthorizeCb, false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context - // FIXME - add this back in - // fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space + fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space // for two copies fromRadio.begin(); From e433249bb1d06605e7199df187d0f58ba2efa271 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 17 Jul 2020 11:14:18 -0700 Subject: [PATCH 17/17] Default back to tbeam in builds, so it will work for others --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b78f387b5..34d1e44fc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = rak815 ; Note: the github actions CI test build can't yet build NRF52 targets +default_envs = tbeam ; Note: the github actions CI test build can't yet build NRF52 targets [common] ; common is not currently used