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,