diff --git a/docs/README.md b/docs/README.md index f6cbf4fe..c39234be 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,10 @@ 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 detailed walk-through aimed at beginners, we recommend [meshtastic.letstalkthis.com](https://meshtastic.letstalkthis.com/). + # Updates Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum. diff --git a/docs/software/TODO.md b/docs/software/TODO.md index f5ff0764..a66a4132 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,6 +2,15 @@ You probably don't care about this section - skip to the next one. +- brf52 ble +- update protocol description per cyclomies +- esp32 pairing +- 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 Items to complete before 1.0. diff --git a/docs/software/bluetooth-api.md b/docs/software/device-api.md similarity index 74% rename from docs/software/bluetooth-api.md rename to docs/software/device-api.md index 78bcb653..30a43213 100644 --- a/docs/software/bluetooth-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) diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index f95e93d4..eaacdb7a 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/platformio.ini b/platformio.ini index b78f387b..34d1e44f 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 diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 5d551d07..61a8fe5e 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -1,8 +1,16 @@ #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" + /// 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/configuration.h b/src/configuration.h index 93490d84..d254b980 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/esp32/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp index 9bc41459..044bbc4e 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/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 3d1a752b..b63241c3 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()) diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 03e5b890..2ae864aa 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -1,23 +1,50 @@ #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); +// 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}; -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 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)); -uint8_t bps = 0; +static BLEDis bledis; // DIS (Device Information Service) helper class instance +static BLEBas blebas; // BAS (Battery Service) helper class instance +static BLEDfu bledfu; // DFU software update helper service + +// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in +// proccess at once +// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; +static uint8_t fromRadioBytes[FromRadio_size]; +static uint8_t toRadioBytes[ToRadio_size]; + +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 +54,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 +65,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 +76,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"); } } } @@ -63,13 +89,15 @@ 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(hrms); + // IncludeService UUID + // 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 @@ -83,74 +111,105 @@ 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 } -void setupHRM(void) +// Just ack that the caller is allowed to read +static void authorizeRead(uint16_t conn_hdl) { - // 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(); + 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 + */ +void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) +{ + if (request->offset == 0) { + // If the read is long, we will get multiple authorize invocations - we only populate data on the first + + 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 + fromRadio.write(fromRadioBytes, numBytes); + } else { + // DEBUG_MSG("Ignoring successor read\n"); + } + authorizeRead(conn_hdl); +} + +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\n"); + + authorizeRead(conn_hdl); +} + +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 + // 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 + // 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(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 + fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space + // for two copies + fromRadio.begin(); + + toRadio.setProperties(CHR_PROPS_WRITE); + toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this! + toRadio.setFixedLen(0); + toRadio.setMaxLen(512); + toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); + 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(); } // FIXME, turn off soft device access for debugging -static bool isSoftDeviceAllowed = false; +static bool isSoftDeviceAllowed = true; void NRF52Bluetooth::setup() { @@ -159,7 +218,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); @@ -167,21 +226,22 @@ 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% 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,60 +254,7 @@ void NRF52Bluetooth::setup() } /// Given a level between 0-100, update the BLE attribute -void updateBatteryLevel(uint8_t level) { - // FIXME - implement -} - -/* -void loop() +void updateBatteryLevel(uint8_t level) { - 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 + blebas.write(level); +} \ No newline at end of file diff --git a/src/nrf52/hardfault.cpp b/src/nrf52/hardfault.cpp index 4cf4dff7..67180c83 100644 --- a/src/nrf52/hardfault.cpp +++ b/src/nrf52/hardfault.cpp @@ -5,47 +5,49 @@ 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("Hard Fault occurred! 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: SCB->CFSR = 0x%08lx\n", SCB->CFSR); if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) { printUsageErrorMsg(SCB->CFSR); @@ -57,21 +59,23 @@ 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]); - asm volatile("bkpt #01"); - while (1) - ; + 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]); } + + FAULT_MSG("Done with fault report - Waiting to reboot\n"); + asm volatile("bkpt #01"); // Enter the debugger if one is connected + while (1) + ; } -void HardFault_Handler(void) +extern "C" void HardFault_Handler(void) { asm volatile(" mrs r0,msp\n" " b HardFault_Impl \n"); diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index 9f81f074..08d2baf0 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 @@ -52,9 +53,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"); @@ -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