ref: e5b73212f6addcfdb5e306df63d7135e543c4f8d
src/components/ble/DfuService.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
#pragma once #include <cstdint> #include <array> #define min // workaround: nimble's min/max macros conflict with libstdc++ #define max #include <host/ble_gap.h> #undef max #undef min namespace Pinetime { namespace System { class SystemTask; } namespace Drivers { class SpiNorFlash; } namespace Controllers { class Ble; class DfuService { public: DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::SpiNorFlash& spiNorFlash); void Init(); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnTimeout(); void Reset(); class NotificationManager { public: NotificationManager(); bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t size); void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t* data, const size_t s); private: TimerHandle_t timer; uint16_t connectionHandle = 0; uint16_t characteristicHandle = 0; size_t size = 0; uint8_t buffer[10]; public: void OnNotificationTimer(); void Reset(); }; class DfuImage { public: DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} { } void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc); void Erase(); void Append(uint8_t* data, size_t size); bool Validate(); bool IsComplete(); private: Pinetime::Drivers::SpiNorFlash& spiNorFlash; static constexpr size_t bufferSize = 200; bool ready = false; size_t chunkSize = 0; size_t totalSize = 0; size_t maxSize = 475136; size_t bufferWriteIndex = 0; size_t totalWriteIndex = 0; static constexpr size_t writeOffset = 0x40000; uint8_t tempBuffer[bufferSize]; uint16_t expectedCrc = 0; void WriteMagicNumber(); uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc); }; private: Pinetime::System::SystemTask& systemTask; Pinetime::Controllers::Ble& bleController; DfuImage dfuImage; NotificationManager notificationManager; static constexpr uint16_t dfuServiceId {0x1530}; static constexpr uint16_t packetCharacteristicId {0x1532}; static constexpr uint16_t controlPointCharacteristicId {0x1531}; static constexpr uint16_t revisionCharacteristicId {0x1534}; uint16_t revision {0x0008}; static constexpr ble_uuid128_t serviceUuid { .u {.type = BLE_UUID_TYPE_128}, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}}; static constexpr ble_uuid128_t packetCharacteristicUuid { .u {.type = BLE_UUID_TYPE_128}, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}}; static constexpr ble_uuid128_t controlPointCharacteristicUuid { .u {.type = BLE_UUID_TYPE_128}, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}}; static constexpr ble_uuid128_t revisionCharacteristicUuid { .u {.type = BLE_UUID_TYPE_128}, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}}; struct ble_gatt_chr_def characteristicDefinition[4]; struct ble_gatt_svc_def serviceDefinition[2]; uint16_t packetCharacteristicHandle; uint16_t controlPointCharacteristicHandle; uint16_t revisionCharacteristicHandle; enum class States : uint8_t { Idle, Init, Start, Data, Validate, Validated }; States state = States::Idle; enum class ImageTypes : uint8_t { NoImage = 0x00, SoftDevice = 0x01, Bootloader = 0x02, SoftDeviceAndBootloader = 0x03, Application = 0x04 }; enum class Opcodes : uint8_t { StartDFU = 0x01, InitDFUParameters = 0x02, ReceiveFirmwareImage = 0x03, ValidateFirmware = 0x04, ActivateImageAndReset = 0x05, PacketReceiptNotificationRequest = 0x08, Response = 0x10, PacketReceiptNotification = 0x11 }; enum class ErrorCodes { NoError = 0x01, InvalidState = 0x02, NotSupported = 0x03, DataSizeExceedsLimits = 0x04, CrcError = 0x05, OperationFailed = 0x06 }; uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; uint32_t bytesReceived = 0; uint32_t softdeviceSize = 0; uint32_t bootloaderSize = 0; uint32_t applicationSize = 0; uint16_t expectedCrc = 0; int SendDfuRevision(os_mbuf* om) const; int WritePacketHandler(uint16_t connectionHandle, os_mbuf* om); int ControlPointHandler(uint16_t connectionHandle, os_mbuf* om); TimerHandle_t timeoutTimer; }; } } |