diff --git a/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.cpp b/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.cpp index 62bdd499d..f2fa7c973 100644 --- a/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.cpp +++ b/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.cpp @@ -1,21 +1,30 @@ -#include "BluetoothUtil.h" #include "BluetoothSoftwareUpdate.h" -#include "configuration.h" -#include -#include -#include -#include -#include +#include "BluetoothUtil.h" #include "CallbackCharacteristic.h" +#include "RadioLibInterface.h" +#include "configuration.h" +#include "lock.h" +#include +#include +#include +#include +#include + +using namespace meshtastic; CRC32 crc; uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) +uint32_t updateExpectedSize, updateActualSize; + +Lock *updateLock; + class TotalSizeCharacteristic : public CallbackCharacteristic { -public: + public: TotalSizeCharacteristic() - : CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ) + : CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e", + BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ) { } @@ -23,8 +32,11 @@ public: { BLEKeepAliveCallbacks::onWrite(c); + 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); @@ -34,32 +46,39 @@ public: 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(); + // 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 } } }; +#define MAX_BLOCKSIZE 512 + class DataCharacteristic : public CallbackCharacteristic { -public: - DataCharacteristic() - : CallbackCharacteristic( - "e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE) - { - } + public: + DataCharacteristic() : CallbackCharacteristic("e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE) {} void onWrite(BLECharacteristic *c) { BLEKeepAliveCallbacks::onWrite(c); + LockGuard g(updateLock); std::string value = c->getValue(); uint32_t len = value.length(); - uint8_t *data = c->getData(); + 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; } }; @@ -67,38 +86,36 @@ static BLECharacteristic *resultC; class CRC32Characteristic : public CallbackCharacteristic { -public: - CRC32Characteristic() - : CallbackCharacteristic( - "4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE) - { - } + public: + CRC32Characteristic() : CallbackCharacteristic("4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE) {} void onWrite(BLECharacteristic *c) { BLEKeepAliveCallbacks::onWrite(c); + 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; - // Check the CRC before asking the update to happen. - if (crc.finalize() != expectedCRC) + 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!\n"); + DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC); result = 0xe0; // FIXME, use real error codes - } - else - { - if (Update.end()) - { + } else { + if (Update.end()) { DEBUG_MSG("OTA done, rebooting in 5 seconds!\n"); rebootAtMsec = millis() + 5000; - } - else - { + } else { DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError()); + + if (RadioLibInterface::instance) + RadioLibInterface::instance->startReceive(); // Resume radio } result = Update.getError(); } @@ -108,8 +125,6 @@ public: } }; - - void bluetoothRebootCheck() { if (rebootAtMsec && millis() > rebootAtMsec) @@ -122,11 +137,15 @@ See bluetooth-api.md */ BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion) { + if (!updateLock) + updateLock = new 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); + 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"); @@ -135,7 +154,8 @@ BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::st 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); + BLECharacteristic *swC = + new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ); swC->setValue(swVersion); service->addCharacteristic(addBLECharacteristic(swC)); @@ -143,7 +163,8 @@ BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::st mfC->setValue(hwVendor); service->addCharacteristic(addBLECharacteristic(mfC)); - BLECharacteristic *hwvC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ); + BLECharacteristic *hwvC = + new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ); hwvC->setValue(hwVersion); service->addCharacteristic(addBLECharacteristic(hwvC)); diff --git a/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.h b/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.h index 60b1f6696..60517a7f2 100644 --- a/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.h +++ b/lib/BluetoothOTA/src/BluetoothSoftwareUpdate.h @@ -1,8 +1,11 @@ #pragma once #include +#include +#include +#include -BLEService *createUpdateService(BLEServer* server, std::string hwVendor, std::string swVersion, std::string hwVersion); +BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion); void destroyUpdateService(); void bluetoothRebootCheck(); \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index a090d132a..5f9149d71 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -19,10 +19,6 @@ class RadioLibInterface : public RadioInterface volatile PendingISR pending = ISR_NONE; volatile bool timerRunning = false; - /** Our ISR code currently needs this to find our active instance - */ - static RadioLibInterface *instance; - /** * Raw ISR handler that just calls our polymorphic method */ @@ -57,6 +53,11 @@ class RadioLibInterface : public RadioInterface /// are _trying_ to receive a packet currently (note - we might just be waiting for one) bool isReceiving; + public: + /** Our ISR code currently needs this to find our active instance + */ + static RadioLibInterface *instance; + /** * Glue functions called from ISR land */ @@ -80,6 +81,13 @@ class RadioLibInterface : public RadioInterface */ virtual bool canSleep(); + /** + * Start waiting to receive a message + * + * External functions can call this method to wake the device from sleep. + */ + virtual void startReceive() = 0; + private: /** start an immediate transmit */ void startSend(MeshPacket *txp); @@ -110,11 +118,6 @@ class RadioLibInterface : public RadioInterface /** are we actively receiving a packet (only called during receiving state) */ virtual bool isActivelyReceiving() = 0; - /** - * Start waiting to receive a message - */ - virtual void startReceive() = 0; - /** * Raw ISR handler that just calls our polymorphic method */