From 5291bcc7de582cfe3a83b94781ee80aa79765706 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 27 Apr 2020 20:16:03 +0200 Subject: Nimble OTA : work in progress --- src/Components/Ble/DfuService.cpp | 157 ++++++++++++++++++-------------- src/Components/Ble/DfuService.h | 69 ++++++-------- src/Components/Ble/NimbleController.cpp | 10 +- src/Components/Ble/NimbleController.h | 8 ++ 4 files changed, 132 insertions(+), 112 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 3099b1bf..5b51ad31 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -1,101 +1,122 @@ -#include "DeviceInformationService.h" +#include "DfuService.h" using namespace Pinetime::Controllers; -constexpr ble_uuid16_t DeviceInformationService::manufacturerNameUuid; -constexpr ble_uuid16_t DeviceInformationService::modelNumberUuid; -constexpr ble_uuid16_t DeviceInformationService::serialNumberUuid; -constexpr ble_uuid16_t DeviceInformationService::fwRevisionUuid; -constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid; -constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid; +constexpr ble_uuid128_t DfuService::serviceUuid; +constexpr ble_uuid128_t DfuService::controlPointCharacteristicUuid; +constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid; +constexpr ble_uuid128_t DfuService::packetCharacteristicUuid; -int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - auto deviceInformationService = static_cast(arg); - return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt); +int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) { + auto dfuService = static_cast(arg); + return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); } -void DeviceInformationService::Init() { - ble_gatts_count_cfg(serviceDefinition); - ble_gatts_add_svcs(serviceDefinition); -} - - -int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt) { - const char *str; - - switch (ble_uuid_u16(ctxt->chr->uuid)) { - case manufacturerNameId: - str = manufacturerName; - break; - case modelNumberId: - str = modelNumber; - break; - case serialNumberId: - str = serialNumber; - break; - case fwRevisionId: - str = fwRevision; - break; - case hwRevisionId: - str = hwRevision; - break; - default: - return BLE_ATT_ERR_UNLIKELY; - } - - int res = os_mbuf_append(ctxt->om, str, strlen(str)); - return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; -} - -DeviceInformationService::DeviceInformationService() : +DfuService::DfuService() : characteristicDefinition{ { - .uuid = (ble_uuid_t *) &manufacturerNameUuid, - .access_cb = DeviceInformationCallback, + .uuid = (ble_uuid_t *) &packetCharacteristicUuid, + .access_cb = DfuServiceCallback, .arg = this, - .flags = BLE_GATT_CHR_F_READ, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + .val_handle = nullptr, }, { - .uuid = (ble_uuid_t *) &modelNumberUuid, - .access_cb = DeviceInformationCallback, + .uuid = (ble_uuid_t *) &controlPointCharacteristicUuid, + .access_cb = DfuServiceCallback, .arg = this, - .flags = BLE_GATT_CHR_F_READ, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY, + .val_handle = nullptr, }, { - .uuid = (ble_uuid_t *) &serialNumberUuid, - .access_cb = DeviceInformationCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_READ, - }, - { - .uuid = (ble_uuid_t *) &fwRevisionUuid, - .access_cb = DeviceInformationCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_READ, - }, - { - .uuid = (ble_uuid_t *) &hwRevisionUuid, - .access_cb = DeviceInformationCallback, + .uuid = (ble_uuid_t *) &revisionCharacteristicUuid, + .access_cb = DfuServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, + .val_handle = &revision, + }, { 0 } + }, - serviceDefinition{ + serviceDefinition { { /* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t *) &deviceInfoUuid, + .uuid = (ble_uuid_t *) &serviceUuid, .characteristics = characteristicDefinition }, { 0 }, } - { + + { + +} + +void DfuService::Init() { + ble_gatts_count_cfg(serviceDefinition); + ble_gatts_add_svcs(serviceDefinition); + } +int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { + + ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&packetCharacteristicUuid, nullptr, &packetCharacteristicHandle); + ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle); + ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle); + + /* * o BLE_GATT_ACCESS_OP_READ_CHR + * o BLE_GATT_ACCESS_OP_WRITE_CHR + * o BLE_GATT_ACCESS_OP_READ_DSC + * o BLE_GATT_ACCESS_OP_WRITE_DSC + * */ + + char* op; + switch(context->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: op = "Read Characteristic"; break; + case BLE_GATT_ACCESS_OP_WRITE_CHR: op = "Write Characteristic"; break; + case BLE_GATT_ACCESS_OP_READ_DSC: op = "Read Descriptor"; break; + case BLE_GATT_ACCESS_OP_WRITE_DSC: op = "Write Descriptor"; break; + } + + if(attributeHandle == packetCharacteristicHandle) { + NRF_LOG_INFO("[DFU] Packet Characteristic : %d - %s", attributeHandle, op); + if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); + uint8_t data[3] {16, 1, 1}; + auto* om = ble_hs_mbuf_from_flat(data, 3); + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + } else if (attributeHandle == controlPointCharacteristicHandle) { + NRF_LOG_INFO("[DFU] ControlPoint Characteristic : %d - %s", attributeHandle, op); + if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); + switch(context->om->om_data[0]) { + case 0x01: {// START DFU + NRF_LOG_INFO("[DFU] -> Start DFU, mode = %d", context->om->om_data[1]); + + } + + break; + } + + } + + } else if(attributeHandle == revisionCharacteristicHandle) { + NRF_LOG_INFO("[DFU] Revision Characteristic : %d - %s", attributeHandle, op); + if(context->op == BLE_GATT_ACCESS_OP_READ_CHR) { + int res = os_mbuf_append(context->om, &revision, 2); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + } else { + NRF_LOG_INFO("[DFU] Unknown Characteristic : %d - %s", attributeHandle, op); + } + + return 0; +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 6249893d..221b6e89 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -6,62 +6,51 @@ namespace Pinetime { namespace Controllers { - class DeviceInformationService { + class DfuService { public: - DeviceInformationService(); + DfuService(); void Init(); - int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt); - + int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); private: - static constexpr uint16_t deviceInfoId {0x180a}; - static constexpr uint16_t manufacturerNameId {0x2a29}; - static constexpr uint16_t modelNumberId {0x2a24}; - static constexpr uint16_t serialNumberId {0x2a25}; - static constexpr uint16_t fwRevisionId {0x2a26}; - static constexpr uint16_t hwRevisionId {0x2a27}; - - static constexpr char* manufacturerName = "Codingfield"; - static constexpr char* modelNumber = "1"; - static constexpr char* serialNumber = "9.8.7.6.5.4"; - static constexpr char* fwRevision = "0.5.0"; - static constexpr char* hwRevision = "1.0.0"; + static constexpr uint16_t dfuServiceId {0x1530}; + static constexpr uint16_t packetCharacteristicId {0x1532}; + static constexpr uint16_t controlPointCharacteristicId {0x1531}; + static constexpr uint16_t revisionCharacteristicId {0x1534}; - static constexpr ble_uuid16_t deviceInfoUuid { - .u { .type = BLE_UUID_TYPE_16 }, - .value = deviceInfoId - }; + uint16_t revision {0x0008}; - static constexpr ble_uuid16_t manufacturerNameUuid { - .u { .type = BLE_UUID_TYPE_16 }, - .value = manufacturerNameId - }; + static constexpr uint16_t opcodeInit = 0x0002; - static constexpr ble_uuid16_t modelNumberUuid { - .u { .type = BLE_UUID_TYPE_16 }, - .value = modelNumberId + 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_uuid16_t serialNumberUuid { - .u { .type = BLE_UUID_TYPE_16 }, - .value = serialNumberId + 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_uuid16_t fwRevisionUuid { - .u { .type = BLE_UUID_TYPE_16 }, - .value = fwRevisionId + 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_uuid16_t hwRevisionUuid { - .u {.type = BLE_UUID_TYPE_16}, - .value = hwRevisionId + 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[6]; + struct ble_gatt_chr_def characteristicDefinition[4]; struct ble_gatt_svc_def serviceDefinition[2]; - - + uint16_t packetCharacteristicHandle; + uint16_t controlPointCharacteristicHandle; + uint16_t revisionCharacteristicHandle; }; } } \ No newline at end of file diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 02f99180..98246b7f 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -73,7 +73,8 @@ void NimbleController::Init() { ble_svc_gatt_init(); deviceInformationService.Init(); - currentTimeClient.Init(); +// currentTimeClient.Init(); + dfuService.Init(); int res; res = ble_hs_util_ensure_addr(0); res = ble_hs_id_infer_auto(0, &addrType); @@ -105,8 +106,9 @@ void NimbleController::StartAdvertising() { // fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE( // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff)); - fields.num_uuids128 = 0; - fields.uuids128_is_complete = 0;; + fields.uuids128 = &dfuServiceUuid; + fields.num_uuids128 = 1; + fields.uuids128_is_complete = 1; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; rsp_fields.name = (uint8_t *)"Pinetime-JF"; @@ -155,7 +157,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) { } else { bleController.Connect(); connectionHandle = event->connect.conn_handle; - ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this); +// ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this); } } break; diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index 99e0c811..25f583f2 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -4,6 +4,7 @@ #include "AlertNotificationClient.h" #include "DeviceInformationService.h" #include "CurrentTimeClient.h" +#include "DfuService.h" #include namespace Pinetime { @@ -31,12 +32,19 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; DateTime& dateTimeController; Pinetime::Controllers::NotificationManager& notificationManager; + DfuService dfuService; DeviceInformationService deviceInformationService; CurrentTimeClient currentTimeClient; AlertNotificationClient alertNotificationClient; uint8_t addrType; uint16_t connectionHandle; + + ble_uuid128_t dfuServiceUuid { + .u { .type = BLE_UUID_TYPE_128}, + .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, + 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00} + }; }; } } -- cgit v1.2.3 From 0195ece317d15bcba7dfbd74b58bb8dbcd3bca0a Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 1 May 2020 15:36:48 +0200 Subject: Working DfuService with quick'n'ugly code --- src/Components/Ble/DfuService.cpp | 78 +++++++++++++++++++++++++++++---- src/Components/Ble/DfuService.h | 6 +++ src/Components/Ble/NimbleController.cpp | 2 +- 3 files changed, 76 insertions(+), 10 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 5b51ad31..107304a9 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -86,30 +86,90 @@ int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandl } if(attributeHandle == packetCharacteristicHandle) { - NRF_LOG_INFO("[DFU] Packet Characteristic : %d - %s", attributeHandle, op); + NRF_LOG_INFO("[DFU] %s Packet", op); if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); - uint8_t data[3] {16, 1, 1}; - auto* om = ble_hs_mbuf_from_flat(data, 3); - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); +// NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); + if(opcode == 1) { + uint8_t data[3]{16, opcode, param}; + NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); + + auto *om = ble_hs_mbuf_from_flat(data, 3); + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + if(dataMode){ + nbPacketReceived++; + bytesReceived += context->om->om_len; + NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); + + if((nbPacketReceived % nbPacketsToNotify) == 0) { + uint8_t data[5]{17, (uint8_t)(bytesReceived>>24),(uint8_t)(bytesReceived>>16), (uint8_t)(bytesReceived>>8), (uint8_t)(bytesReceived&0x000000FF) }; + NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received",bytesReceived); + + auto *om = ble_hs_mbuf_from_flat(data, 5); + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + if(bytesReceived == 175280) { + uint8_t data[3]{16, 3, 1}; + NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); + + auto *om = ble_hs_mbuf_from_flat(data, 3); + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + } + } } else if (attributeHandle == controlPointCharacteristicHandle) { - NRF_LOG_INFO("[DFU] ControlPoint Characteristic : %d - %s", attributeHandle, op); + NRF_LOG_INFO("[DFU] %s ControlPoint", op); if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); +// NRF_LOG_INFO("[DFU] -> Write %dB {%d, %d}", context->om->om_len, context->om->om_data[0], context->om->om_data[1]); switch(context->om->om_data[0]) { case 0x01: {// START DFU NRF_LOG_INFO("[DFU] -> Start DFU, mode = %d", context->om->om_data[1]); - + opcode = 0x01; + param = 1; } + break; + case 0x02: + NRF_LOG_INFO("[DFU] -> Receive init, state (0=RX, 1=Complete) = %d", context->om->om_data[1]); + opcode = 0x02; + param = context->om->om_data[1]; + if(param == 1) { + uint8_t data[3] {16, opcode, param}; + NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); + + auto *om = ble_hs_mbuf_from_flat(data, 3); + + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + break; + case 0x08: + nbPacketsToNotify = context->om->om_data[1]; + NRF_LOG_INFO("[DFU] -> Receive Packet Notification Request, nb packet = %d", nbPacketsToNotify); + break; + case 0x03: + NRF_LOG_INFO("[DFU] -> Starting receive firmware"); + dataMode = true; + break; + case 0x04: { + NRF_LOG_INFO("[DFU] -> Validate firmware"); + uint8_t data[3]{16, 4, 1}; + NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); + auto *om = ble_hs_mbuf_from_flat(data, 3); + + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + } + break; + case 0x05: + NRF_LOG_INFO("[DFU] -> Activate image and reset!"); break; } + } } else if(attributeHandle == revisionCharacteristicHandle) { - NRF_LOG_INFO("[DFU] Revision Characteristic : %d - %s", attributeHandle, op); + NRF_LOG_INFO("[DFU] %s Revision", op); if(context->op == BLE_GATT_ACCESS_OP_READ_CHR) { int res = os_mbuf_append(context->om, &revision, 2); return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 221b6e89..bb643632 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -51,6 +51,12 @@ namespace Pinetime { uint16_t packetCharacteristicHandle; uint16_t controlPointCharacteristicHandle; uint16_t revisionCharacteristicHandle; + uint8_t opcode = 0; + uint8_t param = 0; + uint8_t nbPacketsToNotify = 0; + uint32_t nbPacketReceived = 0; + bool dataMode = false; + uint32_t bytesReceived = 0; }; } } \ No newline at end of file diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 98246b7f..ccb1e6ad 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -231,7 +231,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) { /* Attribute data is contained in event->notify_rx.attr_data. */ default: - NRF_LOG_INFO("Advertising event : %d", event->type); +// NRF_LOG_INFO("Advertising event : %d", event->type); break; } return 0; -- cgit v1.2.3 From 56b527925ce64bc0a9ef4b0ca51a1648b6400e04 Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 1 May 2020 17:58:10 +0200 Subject: Clean code of DfuService --- src/Components/Ble/DfuService.cpp | 221 +++++++++++++++++++++----------------- src/Components/Ble/DfuService.h | 35 +++++- src/sdk_config.h | 6 +- 3 files changed, 155 insertions(+), 107 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 107304a9..bc96dd9b 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -61,8 +61,6 @@ DfuService::DfuService() : void DfuService::Init() { ble_gatts_count_cfg(serviceDefinition); ble_gatts_add_svcs(serviceDefinition); - - } int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { @@ -71,112 +69,137 @@ int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandl ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle); ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle); - /* * o BLE_GATT_ACCESS_OP_READ_CHR - * o BLE_GATT_ACCESS_OP_WRITE_CHR - * o BLE_GATT_ACCESS_OP_READ_DSC - * o BLE_GATT_ACCESS_OP_WRITE_DSC - * */ - - char* op; - switch(context->op) { - case BLE_GATT_ACCESS_OP_READ_CHR: op = "Read Characteristic"; break; - case BLE_GATT_ACCESS_OP_WRITE_CHR: op = "Write Characteristic"; break; - case BLE_GATT_ACCESS_OP_READ_DSC: op = "Read Descriptor"; break; - case BLE_GATT_ACCESS_OP_WRITE_DSC: op = "Write Descriptor"; break; - } - if(attributeHandle == packetCharacteristicHandle) { - NRF_LOG_INFO("[DFU] %s Packet", op); - if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { -// NRF_LOG_INFO("[DFU] -> Write %dB", context->om->om_len); - if(opcode == 1) { - uint8_t data[3]{16, opcode, param}; - NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); - - auto *om = ble_hs_mbuf_from_flat(data, 3); - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - } - if(dataMode){ - nbPacketReceived++; - bytesReceived += context->om->om_len; - NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); - - if((nbPacketReceived % nbPacketsToNotify) == 0) { - uint8_t data[5]{17, (uint8_t)(bytesReceived>>24),(uint8_t)(bytesReceived>>16), (uint8_t)(bytesReceived>>8), (uint8_t)(bytesReceived&0x000000FF) }; - NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received",bytesReceived); + if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) + return WritePacketHandler(connectionHandle, context->om); + else return 0; + } else if(attributeHandle == controlPointCharacteristicHandle) { + if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) + return ControlPointHandler(connectionHandle, context->om); + else return 0; + } else if(attributeHandle == revisionCharacteristicHandle) { + if(context->op == BLE_GATT_ACCESS_OP_READ_CHR) + return SendDfuRevision(context->om); + else return 0; + } else { + NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle); + return 0; + } +} - auto *om = ble_hs_mbuf_from_flat(data, 5); - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - } - if(bytesReceived == 175280) { - uint8_t data[3]{16, 3, 1}; - NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); +int DfuService::SendDfuRevision(os_mbuf *om) const { + int res = os_mbuf_append(om, &revision, sizeof(revision)); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} - auto *om = ble_hs_mbuf_from_flat(data, 3); - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - } +int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { + switch(state) { + case States::Start: { + uint8_t data[] {16, 1, 1}; + SendNotification(connectionHandle, data, 3); + } + return 0; + case States::Data: { + nbPacketReceived++; + bytesReceived += om->om_len; + NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); + + if((nbPacketReceived % nbPacketsToNotify) == 0) { + uint8_t data[5]{static_cast(Opcodes::PacketReceiptNotification), + (uint8_t)(bytesReceived>>24u),(uint8_t)(bytesReceived>>16u), (uint8_t)(bytesReceived>>8u), (uint8_t)(bytesReceived&0x000000FFu) }; + NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received",bytesReceived); + SendNotification(connectionHandle, data, 5); + } + if(bytesReceived == 175280) { + uint8_t data[3]{static_cast(Opcodes::Response), + static_cast(Opcodes::ReceiveFirmwareImage), + static_cast(ErrorCodes::NoError)}; + NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); + SendNotification(connectionHandle, data, 3); + state = States::Validate; } + } + return 0; + default: + // Invalid state + return 0; + } + return 0; +} +int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { + auto opcode = static_cast(om->om_data[0]); + switch(opcode) { + case Opcodes::StartDFU: { + if(state != States::Idle) { + NRF_LOG_INFO("[DFU] -> Start DFU requested, but we are not in Idle state"); + return 0; + } + auto imageType = static_cast(om->om_data[1]); + if(imageType == ImageTypes::Application) { + NRF_LOG_INFO("[DFU] -> Start DFU, mode = Application"); + state = States::Start; + return 0; + } else { + NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType); + return 0; + } } - } else if (attributeHandle == controlPointCharacteristicHandle) { - NRF_LOG_INFO("[DFU] %s ControlPoint", op); - if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { -// NRF_LOG_INFO("[DFU] -> Write %dB {%d, %d}", context->om->om_len, context->om->om_data[0], context->om->om_data[1]); - switch(context->om->om_data[0]) { - case 0x01: {// START DFU - NRF_LOG_INFO("[DFU] -> Start DFU, mode = %d", context->om->om_data[1]); - opcode = 0x01; - param = 1; - } - break; - case 0x02: - NRF_LOG_INFO("[DFU] -> Receive init, state (0=RX, 1=Complete) = %d", context->om->om_data[1]); - opcode = 0x02; - param = context->om->om_data[1]; - if(param == 1) { - uint8_t data[3] {16, opcode, param}; - NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); - - auto *om = ble_hs_mbuf_from_flat(data, 3); - - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - } - break; - case 0x08: - nbPacketsToNotify = context->om->om_data[1]; - NRF_LOG_INFO("[DFU] -> Receive Packet Notification Request, nb packet = %d", nbPacketsToNotify); - break; - case 0x03: - NRF_LOG_INFO("[DFU] -> Starting receive firmware"); - dataMode = true; - break; - case 0x04: { - NRF_LOG_INFO("[DFU] -> Validate firmware"); - uint8_t data[3]{16, 4, 1}; - NRF_LOG_INFO("[DFU] -> Send notification: {%d, %d, %d}", data[0], data[1], data[2]); - - auto *om = ble_hs_mbuf_from_flat(data, 3); - - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - } - break; - case 0x05: - NRF_LOG_INFO("[DFU] -> Activate image and reset!"); - break; + break; + case Opcodes::InitDFUParameters: { + if (state != States::Start) { + NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Start state"); + return 0; + } + bool isInitComplete = (om->om_data[1] != 0); + NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete"); + + if (isInitComplete) { + uint8_t data[3]{static_cast(Opcodes::Response), + static_cast(Opcodes::InitDFUParameters), + (isInitComplete ? uint8_t{1} : uint8_t{0})}; + SendNotification(connectionHandle, data, 3); + return 0; } - - } - - } else if(attributeHandle == revisionCharacteristicHandle) { - NRF_LOG_INFO("[DFU] %s Revision", op); - if(context->op == BLE_GATT_ACCESS_OP_READ_CHR) { - int res = os_mbuf_append(context->om, &revision, 2); - return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + return 0; + case Opcodes::PacketReceiptNotificationRequest: + nbPacketsToNotify = om->om_data[1]; + NRF_LOG_INFO("[DFU] -> Receive Packet Notification Request, nb packet = %d", nbPacketsToNotify); + return 0; + case Opcodes::ReceiveFirmwareImage: + if(state != States::Start) { + NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start state"); + return 0; + } + NRF_LOG_INFO("[DFU] -> Starting receive firmware"); + state = States::Data; + return 0; + case Opcodes::ValidateFirmware: { + if(state != States::Validate) { + NRF_LOG_INFO("[DFU] -> Validate firmware image requested, but we are not in Data state"); + return 0; + } + NRF_LOG_INFO("[DFU] -> Validate firmware"); + state = States::Validated; + uint8_t data[3]{static_cast(Opcodes::Response), + static_cast(Opcodes::ValidateFirmware), + static_cast(ErrorCodes::NoError)}; + SendNotification(connectionHandle, data, 3); + return 0; } - } else { - NRF_LOG_INFO("[DFU] Unknown Characteristic : %d - %s", attributeHandle, op); + case Opcodes::ActivateImageAndReset: + if(state != States::Validated) { + NRF_LOG_INFO("[DFU] -> Activate image and reset requested, but we are not in Validated state"); + return 0; + } + NRF_LOG_INFO("[DFU] -> Activate image and reset!"); + return 0; + default: return 0; } +} - return 0; +void DfuService::SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size) { + auto *om = ble_hs_mbuf_from_flat(data, size); + ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); } diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index bb643632..1b13c00d 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -20,8 +20,6 @@ namespace Pinetime { uint16_t revision {0x0008}; - static constexpr uint16_t opcodeInit = 0x0002; - static constexpr ble_uuid128_t serviceUuid { .u { .type = BLE_UUID_TYPE_128}, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, @@ -51,12 +49,39 @@ namespace Pinetime { uint16_t packetCharacteristicHandle; uint16_t controlPointCharacteristicHandle; uint16_t revisionCharacteristicHandle; - uint8_t opcode = 0; - uint8_t param = 0; + + 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}; + uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; - bool dataMode = false; uint32_t bytesReceived = 0; + + int SendDfuRevision(os_mbuf *om) const; + void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); + int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); + int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om); }; } } \ No newline at end of file diff --git a/src/sdk_config.h b/src/sdk_config.h index 244b21bd..a63eb6fb 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -8460,15 +8460,15 @@ // NRF_LOG_ENABLED - nrf_log - Logger //========================================================== #ifndef NRF_LOG_ENABLED -#define NRF_LOG_ENABLED 1 +#define NRF_LOG_ENABLED 0 #endif #ifndef NRF_LOG_BACKEND_RTT_ENABLED -#define NRF_LOG_BACKEND_RTT_ENABLED 1 +#define NRF_LOG_BACKEND_RTT_ENABLED 0 #endif #ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT -#define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 +#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0 #endif // Log message pool - Configuration of log message pool -- cgit v1.2.3 From 87c6556ad049077ab14398637031ea029b321baf Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 1 May 2020 21:58:31 +0200 Subject: Defer the discovery of services using the system task. --- src/Components/Ble/AlertNotificationClient.cpp | 4 ---- src/Components/Ble/AlertNotificationClient.h | 1 - src/Components/Ble/CurrentTimeClient.cpp | 4 ---- src/Components/Ble/CurrentTimeClient.h | 1 - src/Components/Ble/NimbleController.cpp | 10 +++++++--- src/Components/Ble/NimbleController.h | 2 ++ src/SystemTask/SystemTask.cpp | 16 ++++++++++++++++ src/SystemTask/SystemTask.h | 5 +++-- 8 files changed, 28 insertions(+), 15 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/AlertNotificationClient.cpp b/src/Components/Ble/AlertNotificationClient.cpp index 6e096353..bf4d851c 100644 --- a/src/Components/Ble/AlertNotificationClient.cpp +++ b/src/Components/Ble/AlertNotificationClient.cpp @@ -42,10 +42,6 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const return false; } -void AlertNotificationClient::Init() { - -} - int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_chr *characteristic) { if(error->status != 0 && error->status != BLE_HS_EDONE) { diff --git a/src/Components/Ble/AlertNotificationClient.h b/src/Components/Ble/AlertNotificationClient.h index 7a085b7e..ca4f4e94 100644 --- a/src/Components/Ble/AlertNotificationClient.h +++ b/src/Components/Ble/AlertNotificationClient.h @@ -16,7 +16,6 @@ namespace Pinetime { public: explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::NotificationManager ¬ificationManager); - void Init(); bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service); int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, diff --git a/src/Components/Ble/CurrentTimeClient.cpp b/src/Components/Ble/CurrentTimeClient.cpp index fdebc084..caec39d1 100644 --- a/src/Components/Ble/CurrentTimeClient.cpp +++ b/src/Components/Ble/CurrentTimeClient.cpp @@ -10,10 +10,6 @@ CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeCon } -void CurrentTimeClient::Init() { - -} - bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service) { if(service == nullptr && error->status == BLE_HS_EDONE) { NRF_LOG_INFO("CTS Discovery complete"); diff --git a/src/Components/Ble/CurrentTimeClient.h b/src/Components/Ble/CurrentTimeClient.h index 2278ef15..76caff9f 100644 --- a/src/Components/Ble/CurrentTimeClient.h +++ b/src/Components/Ble/CurrentTimeClient.h @@ -10,7 +10,6 @@ namespace Pinetime { class CurrentTimeClient { public: explicit CurrentTimeClient(DateTime& dateTimeController); - void Init(); bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service); int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_chr *characteristic); diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index ccb1e6ad..f3d271ec 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -73,7 +73,6 @@ void NimbleController::Init() { ble_svc_gatt_init(); deviceInformationService.Init(); -// currentTimeClient.Init(); dfuService.Init(); int res; res = ble_hs_util_ensure_addr(0); @@ -156,8 +155,9 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) { bleController.Disconnect(); } else { bleController.Connect(); + systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleConnected); connectionHandle = event->connect.conn_handle; -// ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this); + // Service discovery is deffered via systemtask } } break; @@ -166,6 +166,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) { NRF_LOG_INFO("disconnect; reason=%d ", event->disconnect.reason); /* Connection terminated; resume advertising. */ + connectionHandle = BLE_HS_CONN_HANDLE_NONE; bleController.Disconnect(); StartAdvertising(); break; @@ -248,7 +249,6 @@ int NimbleController::OnDiscoveryEvent(uint16_t i, const ble_gatt_error *error, ble_gattc_disc_all_chrs(connectionHandle, alertNotificationClient.StartHandle(), alertNotificationClient.EndHandle(), AlertNotificationCharacteristicDiscoveredCallback, this); } - return 0; } alertNotificationClient.OnDiscoveryEvent(i, error, service); @@ -295,6 +295,10 @@ int NimbleController::OnANSDescriptorDiscoveryEventCallback(uint16_t connectionH return alertNotificationClient.OnDescriptorDiscoveryEventCallback(connectionHandle, error, characteristicValueHandle, descriptor); } +void NimbleController::StartDiscovery() { + ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this); +} + diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index 25f583f2..945d3329 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -26,6 +26,8 @@ namespace Pinetime { int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute); int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error, uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor); + + void StartDiscovery(); private: static constexpr char* deviceName = "Pinetime-JF"; Pinetime::System::SystemTask& systemTask; diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 6516f68b..43ac73f9 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -100,9 +100,25 @@ void SystemTask::Work() { case Messages::OnNewNotification: displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewNotification); break; + case Messages::BleConnected: + isBleDiscoveryTimerRunning = true; + bleDiscoveryTimer = 5; + break; default: break; } } + + if(isBleDiscoveryTimerRunning) { + if(bleDiscoveryTimer == 0) { + isBleDiscoveryTimerRunning = false; + // Services discovery is deffered from 3 seconds to avoid the conflicts between the host communicating with the + // tharget and vice-versa. I'm not sure if this is the right way to handle this... + nimbleController.StartDiscovery(); + } else { + bleDiscoveryTimer--; + } + } + uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); dateTimeController.UpdateTime(systick_counter); batteryController.Update(); diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index 5eba391b..65cfdd8f 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -14,7 +14,7 @@ namespace Pinetime { namespace System { class SystemTask { public: - enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification + enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, BleConnected }; SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, Drivers::Cst816S &touchPanel, @@ -58,7 +58,8 @@ namespace Pinetime { static void Process(void* instance); void Work(); - + bool isBleDiscoveryTimerRunning = false; + uint8_t bleDiscoveryTimer = 0; }; } -- cgit v1.2.3 From e20fdfa494ed8b1b6a62b71ca605a6a801e54e4e Mon Sep 17 00:00:00 2001 From: JF Date: Sat, 2 May 2020 14:16:57 +0200 Subject: Add new screen that is displayed during the OTA transfert. --- src/CMakeLists.txt | 2 ++ src/Components/Ble/BleController.cpp | 16 ++++++++++ src/Components/Ble/BleController.h | 12 ++++++++ src/Components/Ble/DfuService.cpp | 13 +++++++- src/Components/Ble/DfuService.h | 9 +++++- src/Components/Ble/NimbleController.cpp | 1 + src/Components/Ble/NimbleController.h | 2 +- src/DisplayApp/DisplayApp.cpp | 12 ++++++++ src/DisplayApp/DisplayApp.h | 2 +- src/DisplayApp/Screens/FirmwareUpdate.cpp | 49 +++++++++++++++++++++++++++++++ src/DisplayApp/Screens/FirmwareUpdate.h | 39 ++++++++++++++++++++++++ src/SystemTask/SystemTask.cpp | 6 ++++ src/SystemTask/SystemTask.h | 3 +- 13 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 src/DisplayApp/Screens/FirmwareUpdate.cpp create mode 100644 src/DisplayApp/Screens/FirmwareUpdate.h (limited to 'src/Components/Ble') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 003fec51..2a9614e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -305,6 +305,7 @@ list(APPEND SOURCE_FILES DisplayApp/Screens/Brightness.cpp DisplayApp/Screens/ScreenList.cpp DisplayApp/Screens/Label.cpp + DisplayApp/Screens/FirmwareUpdate.cpp main.cpp drivers/St7789.cpp drivers/SpiMaster.cpp @@ -354,6 +355,7 @@ set(INCLUDE_FILES DisplayApp/Screens/Brightness.h DisplayApp/Screens/ScreenList.h DisplayApp/Screens/Label.h + DisplayApp/Screens/FirmwareUpdate.h drivers/St7789.h drivers/SpiMaster.h drivers/Watchdog.h diff --git a/src/Components/Ble/BleController.cpp b/src/Components/Ble/BleController.cpp index 5fa51688..2b396e12 100644 --- a/src/Components/Ble/BleController.cpp +++ b/src/Components/Ble/BleController.cpp @@ -12,4 +12,20 @@ void Ble::Disconnect() { isConnected = false; } +void Ble::StartFirmwareUpdate() { + isFirmwareUpdating = true; +} + +void Ble::StopFirmwareUpdate() { + isFirmwareUpdating = false; +} + +void Ble::FirmwareUpdateTotalBytes(uint32_t totalBytes) { + firmwareUpdateTotalBytes = totalBytes; +} + +void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) { + firmwareUpdateCurrentBytes = currentBytes; +} + diff --git a/src/Components/Ble/BleController.h b/src/Components/Ble/BleController.h index f2bd77e0..65a5ef8f 100644 --- a/src/Components/Ble/BleController.h +++ b/src/Components/Ble/BleController.h @@ -12,8 +12,20 @@ namespace Pinetime { bool IsConnected() const {return isConnected;} void Connect(); void Disconnect(); + + void StartFirmwareUpdate(); + void StopFirmwareUpdate(); + void FirmwareUpdateTotalBytes(uint32_t totalBytes); + void FirmwareUpdateCurrentBytes(uint32_t currentBytes); + + bool IsFirmwareUpdating() const { return isFirmwareUpdating; } + uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } + uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } private: bool isConnected = false; + bool isFirmwareUpdating = false; + uint32_t firmwareUpdateTotalBytes = 0; + uint32_t firmwareUpdateCurrentBytes = 0; }; } diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index bc96dd9b..2870d7f0 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -1,3 +1,5 @@ +#include +#include #include "DfuService.h" using namespace Pinetime::Controllers; @@ -13,7 +15,9 @@ int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); } -DfuService::DfuService() : +DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController) : + systemTask{systemTask}, + bleController{bleController}, characteristicDefinition{ { .uuid = (ble_uuid_t *) &packetCharacteristicUuid, @@ -102,6 +106,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { case States::Data: { nbPacketReceived++; bytesReceived += om->om_len; + bleController.FirmwareUpdateCurrentBytes(bytesReceived); NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); if((nbPacketReceived % nbPacketsToNotify) == 0) { @@ -139,6 +144,10 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { if(imageType == ImageTypes::Application) { NRF_LOG_INFO("[DFU] -> Start DFU, mode = Application"); state = States::Start; + bleController.StartFirmwareUpdate(); + bleController.FirmwareUpdateTotalBytes(175280); + bleController.FirmwareUpdateCurrentBytes(0); + systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateStarted); return 0; } else { NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType); @@ -194,6 +203,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { return 0; } NRF_LOG_INFO("[DFU] -> Activate image and reset!"); + bleController.StopFirmwareUpdate(); + systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished); return 0; default: return 0; } diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 1b13c00d..7077bf02 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -5,14 +5,21 @@ #include namespace Pinetime { + namespace System { + class SystemTask; + } namespace Controllers { + class Ble; class DfuService { public: - DfuService(); + DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController); void Init(); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); private: + Pinetime::System::SystemTask& systemTask; + Pinetime::Controllers::Ble& bleController; + static constexpr uint16_t dfuServiceId {0x1530}; static constexpr uint16_t packetCharacteristicId {0x1532}; static constexpr uint16_t controlPointCharacteristicId {0x1531}; diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index f3d271ec..f16d8af0 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -29,6 +29,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, bleController{bleController}, dateTimeController{dateTimeController}, notificationManager{notificationManager}, + dfuService{systemTask, bleController}, currentTimeClient{dateTimeController}, alertNotificationClient{systemTask, notificationManager} { diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index 945d3329..c4922bae 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -34,7 +34,7 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; DateTime& dateTimeController; Pinetime::Controllers::NotificationManager& notificationManager; - DfuService dfuService; + Pinetime::Controllers::DfuService dfuService; DeviceInformationService deviceInformationService; CurrentTimeClient currentTimeClient; diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 1b4515e0..c42639c7 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "../SystemTask/SystemTask.h" using namespace Pinetime::Applications; @@ -157,6 +158,17 @@ void DisplayApp::Refresh() { // toggle = true; // } + break; + case Messages::BleFirmwareUpdateStarted: + lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); + currentScreen.reset(nullptr); + currentScreen.reset(new Screens::FirmwareUpdate(this, bleController)); + + break; + case Messages::BleFirmwareUpdateFinished: + lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); + currentScreen.reset(nullptr); + currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); break; } } diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 09f0d1cd..b45a0bee 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -30,7 +30,7 @@ namespace Pinetime { public: enum class States {Idle, Running}; enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, SwitchScreen,ButtonPushed, - NewNotification + NewNotification, BleFirmwareUpdateStarted, BleFirmwareUpdateFinished }; enum class FullRefreshDirections { None, Up, Down }; diff --git a/src/DisplayApp/Screens/FirmwareUpdate.cpp b/src/DisplayApp/Screens/FirmwareUpdate.cpp new file mode 100644 index 00000000..f3cf42f9 --- /dev/null +++ b/src/DisplayApp/Screens/FirmwareUpdate.cpp @@ -0,0 +1,49 @@ +#include +#include "FirmwareUpdate.h" +#include "../DisplayApp.h" + +using namespace Pinetime::Applications::Screens; +extern lv_font_t jetbrains_mono_extrabold_compressed; +extern lv_font_t jetbrains_mono_bold_20; + + +FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Ble& bleController) : + Screen(app), bleController{bleController} { + + titleLabel = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(titleLabel, "Firmware update"); + lv_obj_set_auto_realign(titleLabel, true); + lv_obj_align(titleLabel, NULL, LV_ALIGN_IN_TOP_MID, 0, 50); + + bar1 = lv_bar_create(lv_scr_act(), NULL); + lv_obj_set_size(bar1, 200, 30); + lv_obj_align(bar1, NULL, LV_ALIGN_CENTER, 0, 0); + lv_bar_set_anim_time(bar1, 10); + lv_bar_set_range(bar1, 0, 100); + lv_bar_set_value(bar1, 0, LV_ANIM_OFF); + + percentLabel = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(percentLabel, ""); + lv_obj_set_auto_realign(percentLabel, true); + lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60); +} + +FirmwareUpdate::~FirmwareUpdate() { + lv_obj_clean(lv_scr_act()); +} + +bool FirmwareUpdate::Refresh() { + float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f; + float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f; + int16_t pc = (current / total) * 100.0f; + sprintf(percentStr, "%d %%", pc); + lv_label_set_text(percentLabel, percentStr); + + lv_bar_set_value(bar1, pc, LV_ANIM_OFF); + return running; +} + +bool FirmwareUpdate::OnButtonPushed() { + running = false; + return true; +} diff --git a/src/DisplayApp/Screens/FirmwareUpdate.h b/src/DisplayApp/Screens/FirmwareUpdate.h new file mode 100644 index 00000000..a4cbec62 --- /dev/null +++ b/src/DisplayApp/Screens/FirmwareUpdate.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include "Screen.h" +#include +#include +#include +#include +#include +#include "../Fonts/lcdfont14.h" +#include "../Fonts/lcdfont70.h" +#include "../../Version.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + + class FirmwareUpdate : public Screen{ + public: + FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController); + ~FirmwareUpdate() override; + + bool Refresh() override; + bool OnButtonPushed() override; + + private: + Pinetime::Controllers::Ble& bleController; + lv_obj_t * bar1; + lv_obj_t * percentLabel; + lv_obj_t * titleLabel; + char percentStr[10]; + bool running = true; + + }; + } + } +} diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 43ac73f9..21298ab6 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -104,6 +104,12 @@ void SystemTask::Work() { isBleDiscoveryTimerRunning = true; bleDiscoveryTimer = 5; break; + case Messages::BleFirmwareUpdateStarted: + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateStarted); + break; + case Messages::BleFirmwareUpdateFinished: + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateFinished); + break; default: break; } } diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index 65cfdd8f..d3498c1f 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -14,7 +14,8 @@ namespace Pinetime { namespace System { class SystemTask { public: - enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, BleConnected + enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, BleConnected, + BleFirmwareUpdateStarted, BleFirmwareUpdateFinished }; SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, Drivers::Cst816S &touchPanel, -- cgit v1.2.3 From 59287e518ca4c6feb058c3746f5d3782adcea5d2 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 3 May 2020 14:27:48 +0200 Subject: Improve dfu state machine --- src/Components/Ble/DfuService.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 2870d7f0..d6c17919 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -99,8 +99,11 @@ int DfuService::SendDfuRevision(os_mbuf *om) const { int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { switch(state) { case States::Start: { + NRF_LOG_INFO("[DFU] -> Start data received"); + uint8_t data[] {16, 1, 1}; SendNotification(connectionHandle, data, 3); + state = States::Init; } return 0; case States::Data: { @@ -134,12 +137,18 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { auto opcode = static_cast(om->om_data[0]); + NRF_LOG_INFO("[DFU] -> ControlPointHandler"); + switch(opcode) { case Opcodes::StartDFU: { - if(state != States::Idle) { + if(state != States::Idle && state != States::Start) { NRF_LOG_INFO("[DFU] -> Start DFU requested, but we are not in Idle state"); return 0; } + if(state == States::Start) { + NRF_LOG_INFO("[DFU] -> Start DFU requested, but we are already in Start state"); + return 0; + } auto imageType = static_cast(om->om_data[1]); if(imageType == ImageTypes::Application) { NRF_LOG_INFO("[DFU] -> Start DFU, mode = Application"); @@ -156,8 +165,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { } break; case Opcodes::InitDFUParameters: { - if (state != States::Start) { - NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Start state"); + if (state != States::Init) { + NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state"); return 0; } bool isInitComplete = (om->om_data[1] != 0); @@ -167,6 +176,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::InitDFUParameters), (isInitComplete ? uint8_t{1} : uint8_t{0})}; + NRF_LOG_INFO("SEND NOTIF : %d %d %d", data[0], data[1], data[2]); SendNotification(connectionHandle, data, 3); return 0; } @@ -177,8 +187,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Receive Packet Notification Request, nb packet = %d", nbPacketsToNotify); return 0; case Opcodes::ReceiveFirmwareImage: - if(state != States::Start) { - NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start state"); + if(state != States::Init) { + NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start Init"); return 0; } NRF_LOG_INFO("[DFU] -> Starting receive firmware"); @@ -212,5 +222,6 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { void DfuService::SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size) { auto *om = ble_hs_mbuf_from_flat(data, size); - ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + auto ret = ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); + ASSERT(ret == 0); } -- cgit v1.2.3 From f96c048debc84bf2ccd10c4e7356e8e20df9bb3a Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 3 May 2020 15:48:42 +0200 Subject: Read and log info from Start and Ini packets. --- src/Components/Ble/DfuService.cpp | 26 +++++++++++++++++++++++--- src/Components/Ble/DfuService.h | 4 ++++ 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index d6c17919..22983a83 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -99,13 +99,33 @@ int DfuService::SendDfuRevision(os_mbuf *om) const { int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { switch(state) { case States::Start: { - NRF_LOG_INFO("[DFU] -> Start data received"); + softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24); + bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); + applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24); + NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); uint8_t data[] {16, 1, 1}; SendNotification(connectionHandle, data, 3); state = States::Init; } return 0; + case States::Init: { + uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8); + uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8); + uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); + uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8); + uint16_t sd[softdeviceArrayLength]; + for(int i = 0; i < softdeviceArrayLength; i++) { + sd[i] = om->om_data[10 + (i*2)] + (om->om_data[(i*2)+1] << 8); + } + uint16_t crc = om->om_data[10 + (softdeviceArrayLength*2)] + (om->om_data[10 + (softdeviceArrayLength*2)] << 8); + + NRF_LOG_INFO("[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %d", + deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], crc); + + return 0; + } + case States::Data: { nbPacketReceived++; bytesReceived += om->om_len; @@ -114,11 +134,11 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { if((nbPacketReceived % nbPacketsToNotify) == 0) { uint8_t data[5]{static_cast(Opcodes::PacketReceiptNotification), - (uint8_t)(bytesReceived>>24u),(uint8_t)(bytesReceived>>16u), (uint8_t)(bytesReceived>>8u), (uint8_t)(bytesReceived&0x000000FFu) }; + (uint8_t)(bytesReceived&0x000000FFu),(uint8_t)(bytesReceived>>8u), (uint8_t)(bytesReceived>>16u),(uint8_t)(bytesReceived>>24u) }; NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received",bytesReceived); SendNotification(connectionHandle, data, 5); } - if(bytesReceived == 175280) { + if(bytesReceived == applicationSize) { uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 7077bf02..f59ba2c9 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -85,6 +85,10 @@ namespace Pinetime { uint32_t nbPacketReceived = 0; uint32_t bytesReceived = 0; + uint32_t softdeviceSize = 0; + uint32_t bootloaderSize = 0; + uint32_t applicationSize = 0; + int SendDfuRevision(os_mbuf *om) const; void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); -- cgit v1.2.3 From 0b8e6c3fa20457bce931b1d289f187e46fc68307 Mon Sep 17 00:00:00 2001 From: JF Date: Thu, 7 May 2020 19:53:51 +0200 Subject: Add SPI NOR Flash driver, WIP. --- src/CMakeLists.txt | 4 +++ src/Components/Ble/NimbleController.cpp | 6 ++-- src/SystemTask/SystemTask.cpp | 6 ++-- src/SystemTask/SystemTask.h | 5 +++- src/drivers/Spi.cpp | 29 ++++++++++++++++++ src/drivers/Spi.h | 33 ++++++++++++++++++++ src/drivers/SpiMaster.cpp | 53 ++++++++++++++++++++++++++++----- src/drivers/SpiMaster.h | 5 ++-- src/drivers/SpiNorFlash.cpp | 36 ++++++++++++++++++++++ src/drivers/SpiNorFlash.h | 28 +++++++++++++++++ src/drivers/St7789.cpp | 9 +++--- src/drivers/St7789.h | 6 ++-- src/main.cpp | 16 ++++++---- src/sdk_config.h | 6 ++-- 14 files changed, 212 insertions(+), 30 deletions(-) create mode 100644 src/drivers/Spi.cpp create mode 100644 src/drivers/Spi.h create mode 100644 src/drivers/SpiNorFlash.cpp create mode 100644 src/drivers/SpiNorFlash.h (limited to 'src/Components/Ble') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a9614e7..e8e5726b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -308,7 +308,9 @@ list(APPEND SOURCE_FILES DisplayApp/Screens/FirmwareUpdate.cpp main.cpp drivers/St7789.cpp + drivers/SpiNorFlash.cpp drivers/SpiMaster.cpp + drivers/Spi.cpp drivers/Watchdog.cpp drivers/DebugPins.cpp Components/Battery/BatteryController.cpp @@ -357,7 +359,9 @@ set(INCLUDE_FILES DisplayApp/Screens/Label.h DisplayApp/Screens/FirmwareUpdate.h drivers/St7789.h + drivers/SpiNorFlash.h drivers/SpiMaster.h + drivers/Spi.h drivers/Watchdog.h drivers/DebugPins.h Components/Battery/BatteryController.h diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 23bd3e2f..1175022e 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -122,14 +122,14 @@ void NimbleController::StartAdvertising() { int res; res = ble_gap_adv_set_fields(&fields); - ASSERT(res == 0); +// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync) res = ble_gap_adv_rsp_set_fields(&rsp_fields); - ASSERT(res == 0); +// ASSERT(res == 0); res = ble_gap_adv_start(addrType, NULL, 10000, &adv_params, GAPEventCallback, this); - ASSERT(res == 0); +// ASSERT(res == 0); } int OnAllSvrDisco(uint16_t conn_handle, diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 30ea568b..c29a932a 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -14,12 +14,13 @@ using namespace Pinetime::System; -SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, Drivers::Cst816S &touchPanel, +SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, + Pinetime::Drivers::SpiNorFlash& spiNorFlash, Drivers::Cst816S &touchPanel, Components::LittleVgl &lvgl, Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime &dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager) : - spi{spi}, lcd{lcd}, touchPanel{touchPanel}, lvgl{lvgl}, batteryController{batteryController}, + spi{spi}, lcd{lcd}, spiNorFlash{spiNorFlash}, touchPanel{touchPanel}, lvgl{lvgl}, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager}, nimbleController(*this, bleController,dateTimeController, notificationManager) { @@ -50,6 +51,7 @@ void SystemTask::Work() { spi.Init(); lcd.Init(); + spiNorFlash.Init(); touchPanel.Init(); batteryController.Init(); diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index d3498c1f..53e69fa7 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace Pinetime { namespace System { @@ -18,7 +19,8 @@ namespace Pinetime { BleFirmwareUpdateStarted, BleFirmwareUpdateFinished }; - SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, Drivers::Cst816S &touchPanel, + SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, + Pinetime::Drivers::SpiNorFlash& spiNorFlash, Drivers::Cst816S &touchPanel, Components::LittleVgl &lvgl, Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime &dateTimeController, @@ -35,6 +37,7 @@ namespace Pinetime { Pinetime::Drivers::SpiMaster& spi; Pinetime::Drivers::St7789& lcd; + Pinetime::Drivers::SpiNorFlash& spiNorFlash; Pinetime::Drivers::Cst816S& touchPanel; Pinetime::Components::LittleVgl& lvgl; Pinetime::Controllers::Battery& batteryController; diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp new file mode 100644 index 00000000..76490aed --- /dev/null +++ b/src/drivers/Spi.cpp @@ -0,0 +1,29 @@ +#include +#include "Spi.h" + +using namespace Pinetime::Drivers; + +Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : + spiMaster{spiMaster}, pinCsn{pinCsn} { + +} + +bool Spi::Write(const uint8_t *data, size_t size) { + return spiMaster.Write(pinCsn, data, size); +} + +bool Spi::Read(uint8_t *data, size_t size) { + return spiMaster.Read(pinCsn, data, size); +} + +void Spi::Sleep() { + // TODO sleep spi + nrf_gpio_cfg_default(pinCsn); +} + +bool Spi::Init() { + nrf_gpio_pin_set(pinCsn); /* disable Set slave select (inactive high) */ + return true; +} + + diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h new file mode 100644 index 00000000..7e155582 --- /dev/null +++ b/src/drivers/Spi.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include "BufferProvider.h" +#include "SpiMaster.h" + +namespace Pinetime { + namespace Drivers { + class Spi { + public: + Spi(SpiMaster& spiMaster, uint8_t pinCsn); + Spi(const Spi&) = delete; + Spi& operator=(const Spi&) = delete; + Spi(Spi&&) = delete; + Spi& operator=(Spi&&) = delete; + + bool Init(); + bool Write(const uint8_t* data, size_t size); + bool Read(uint8_t* data, size_t size); + void Sleep(); + void Wakeup(); + + private: + SpiMaster& spiMaster; + uint8_t pinCsn; + }; + } +} diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 71986054..7e5bb935 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -19,8 +19,8 @@ bool SpiMaster::Init() { nrf_gpio_pin_clear(params.pinMOSI); nrf_gpio_cfg_output(params.pinMOSI); nrf_gpio_cfg_input(params.pinMISO, NRF_GPIO_PIN_NOPULL); - nrf_gpio_cfg_output(params.pinCSN); - pinCsn = params.pinCSN; +// nrf_gpio_cfg_output(params.pinCSN); +// pinCsn = params.pinCSN; switch(spi) { case SpiModule::SPI0: spiBaseAddress = NRF_SPIM0; break; @@ -32,7 +32,6 @@ bool SpiMaster::Init() { spiBaseAddress->PSELSCK = params.pinSCK; spiBaseAddress->PSELMOSI = params.pinMOSI; spiBaseAddress->PSELMISO = params.pinMISO; - nrf_gpio_pin_set(pinCsn); /* disable Set slave select (inactive high) */ uint32_t frequency; switch(params.Frequency) { @@ -122,7 +121,7 @@ void SpiMaster::OnEndEvent() { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } - nrf_gpio_pin_set(pinCsn); + nrf_gpio_pin_set(this->pinCsn); } } @@ -140,20 +139,33 @@ void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(const uint8_t *data, size_t size) { +void SpiMaster::PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size) { + spiBaseAddress->TXD.PTR = 0; + spiBaseAddress->TXD.MAXCNT = 0; + spiBaseAddress->TXD.LIST = 0; + spiBaseAddress->RXD.PTR = bufferAddress; + spiBaseAddress->RXD.MAXCNT = size; + spiBaseAddress->RXD.LIST = 0; + spiBaseAddress->EVENTS_END = 0; +} + + +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t *data, size_t size) { if(data == nullptr) return false; taskToNotify = xTaskGetCurrentTaskHandle(); while(busy) { asm("nop"); } + this->pinCsn = pinCsn; + if(size == 1) { SetupWorkaroundForFtpan58(spiBaseAddress, 0,0); } else { DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } - nrf_gpio_pin_clear(pinCsn); + nrf_gpio_pin_clear(this->pinCsn); currentBufferAddr = (uint32_t)data; currentBufferSize = size; @@ -173,6 +185,33 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { return true; } +bool SpiMaster::Read(uint8_t pinCsn, uint8_t *data, size_t size) { + while(busy) { + asm("nop"); + } + taskToNotify = nullptr; + + this->pinCsn = pinCsn; + SetupWorkaroundForFtpan58(spiBaseAddress, 0,0); + + nrf_gpio_pin_clear(this->pinCsn); + + currentBufferAddr = 0; + currentBufferSize = 0; + busy = true; + + PrepareRx((uint32_t)data, size); + spiBaseAddress->TASKS_START = 1; + + while (spiBaseAddress->EVENTS_END == 0); + nrf_gpio_pin_set(this->pinCsn); + + busy = false; + + return true; +} + + void SpiMaster::Sleep() { while(spiBaseAddress->ENABLE != 0) { spiBaseAddress->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); @@ -180,7 +219,6 @@ void SpiMaster::Sleep() { nrf_gpio_cfg_default(params.pinSCK); nrf_gpio_cfg_default(params.pinMOSI); nrf_gpio_cfg_default(params.pinMISO); - nrf_gpio_cfg_default(params.pinCSN); } void SpiMaster::Wakeup() { @@ -188,3 +226,4 @@ void SpiMaster::Wakeup() { } + diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 362f480c..24b39b97 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -22,7 +22,6 @@ namespace Pinetime { uint8_t pinSCK; uint8_t pinMOSI; uint8_t pinMISO; - uint8_t pinCSN; }; SpiMaster(const SpiModule spi, const Parameters& params); @@ -32,7 +31,8 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size); + bool Write(uint8_t pinCsn, const uint8_t* data, size_t size); + bool Read(uint8_t pinCsn, uint8_t* data, size_t size); void OnStartedEvent(); void OnEndEvent(); @@ -44,6 +44,7 @@ namespace Pinetime { void SetupWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void DisableWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); + void PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size); NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp new file mode 100644 index 00000000..d19548ee --- /dev/null +++ b/src/drivers/SpiNorFlash.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include "SpiNorFlash.h" +#include "Spi.h" + +using namespace Pinetime::Drivers; + +SpiNorFlash::SpiNorFlash(Spi& spi) : spi{spi} { + +} + +void SpiNorFlash::Init() { + uint8_t cmd = 0x9F; + spi.Write(&cmd, 1); + + uint8_t data[3]; + data[0] = 0; + data[1] = 0; + data[2] = 0; + spi.Read(data, 3); + + NRF_LOG_INFO("Manufacturer : %d, Device : %d", data[0], (data[1] + (data[2]<<8))); +} + +void SpiNorFlash::Uninit() { + +} + +void SpiNorFlash::Sleep() { + +} + +void SpiNorFlash::Wakeup() { + +} diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h new file mode 100644 index 00000000..839a1c2a --- /dev/null +++ b/src/drivers/SpiNorFlash.h @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace Pinetime { + namespace Drivers { + class Spi; + class SpiNorFlash { + public: + explicit SpiNorFlash(Spi& spi); + SpiNorFlash(const SpiNorFlash&) = delete; + SpiNorFlash& operator=(const SpiNorFlash&) = delete; + SpiNorFlash(SpiNorFlash&&) = delete; + SpiNorFlash& operator=(SpiNorFlash&&) = delete; + + void Init(); + void Uninit(); + + + void Sleep(); + void Wakeup(); + private: + Spi& spi; + + }; + } +} + + diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index db7c27e2..09269afd 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -1,16 +1,17 @@ #include #include #include "St7789.h" -#include "SpiMaster.h" +#include "Spi.h" using namespace Pinetime::Drivers; -St7789::St7789(SpiMaster &spiMaster, uint8_t pinDataCommand) : spi{spiMaster}, pinDataCommand{pinDataCommand} { +St7789::St7789(Spi &spi, uint8_t pinDataCommand) : spi{spi}, pinDataCommand{pinDataCommand} { } void St7789::Init() { + spi.Init(); nrf_gpio_cfg_output(pinDataCommand); nrf_gpio_cfg_output(26); nrf_gpio_pin_set(26); @@ -173,11 +174,11 @@ void St7789::HardwareReset() { void St7789::Sleep() { SleepIn(); nrf_gpio_cfg_default(pinDataCommand); - spi.Sleep(); +// spi.Sleep(); // TODO sleep SPI } void St7789::Wakeup() { - spi.Wakeup(); +// spi.Wakeup(); // TODO wake up SPI nrf_gpio_cfg_output(pinDataCommand); // TODO why do we need to reset the controller? diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 3721b184..0b94cf24 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -3,10 +3,10 @@ namespace Pinetime { namespace Drivers { - class SpiMaster; + class Spi; class St7789 { public: - explicit St7789(SpiMaster& spiMaster, uint8_t pinDataCommand); + explicit St7789(Spi& spi, uint8_t pinDataCommand); St7789(const St7789&) = delete; St7789& operator=(const St7789&) = delete; St7789(St7789&&) = delete; @@ -29,7 +29,7 @@ namespace Pinetime { void Sleep(); void Wakeup(); private: - SpiMaster& spi; + Spi& spi; uint8_t pinDataCommand; uint8_t verticalScrollingStartAddress = 0; diff --git a/src/main.cpp b/src/main.cpp index e0e9b65e..a48395d0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "Components/Ble/BleController.h" #include #include +#include #include #include #include @@ -38,7 +39,8 @@ Pinetime::Logging::DummyLogger logger; static constexpr uint8_t pinSpiSck = 2; static constexpr uint8_t pinSpiMosi = 3; static constexpr uint8_t pinSpiMiso = 4; -static constexpr uint8_t pinSpiCsn = 25; +static constexpr uint8_t pinSpiFlashCsn = 5; +static constexpr uint8_t pinLcdCsn = 25; static constexpr uint8_t pinLcdDataCommand = 18; Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, { @@ -47,11 +49,15 @@ Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz, pinSpiSck, pinSpiMosi, - pinSpiMiso, - pinSpiCsn + pinSpiMiso } }; -Pinetime::Drivers::St7789 lcd {spi, pinLcdDataCommand}; + +Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn}; +Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand}; + +Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn}; +Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; Pinetime::Drivers::Cst816S touchPanel {}; Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; @@ -207,7 +213,7 @@ int main(void) { debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback); - systemTask.reset(new Pinetime::System::SystemTask(spi, lcd, touchPanel, lvgl, batteryController, bleController, + systemTask.reset(new Pinetime::System::SystemTask(spi, lcd, spiNorFlash, touchPanel, lvgl, batteryController, bleController, dateTimeController, notificationManager)); systemTask->Start(); nimble_port_init(); diff --git a/src/sdk_config.h b/src/sdk_config.h index a63eb6fb..244b21bd 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -8460,15 +8460,15 @@ // NRF_LOG_ENABLED - nrf_log - Logger //========================================================== #ifndef NRF_LOG_ENABLED -#define NRF_LOG_ENABLED 0 +#define NRF_LOG_ENABLED 1 #endif #ifndef NRF_LOG_BACKEND_RTT_ENABLED -#define NRF_LOG_BACKEND_RTT_ENABLED 0 +#define NRF_LOG_BACKEND_RTT_ENABLED 1 #endif #ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT -#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0 +#define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 #endif // Log message pool - Configuration of log message pool -- cgit v1.2.3 From ee05577dd62c64d0e6a2e497b75710c7a1351557 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 11 May 2020 18:50:37 +0200 Subject: Fix race conditions on SPI and integrate the SPI NOR Flash driver into DFUService (WIP) --- src/Components/Ble/DfuService.cpp | 17 ++++- src/Components/Ble/DfuService.h | 7 ++- src/Components/Ble/NimbleController.cpp | 6 +- src/Components/Ble/NimbleController.h | 8 ++- src/DisplayApp/LittleVgl.cpp | 3 + src/SystemTask/SystemTask.cpp | 14 ++--- src/drivers/Spi.cpp | 11 +++- src/drivers/Spi.h | 3 +- src/drivers/SpiMaster.cpp | 85 +++++++++++++++++++------ src/drivers/SpiMaster.h | 11 +++- src/drivers/SpiNorFlash.cpp | 108 +++++++++++++++++++++++++++++--- src/drivers/SpiNorFlash.h | 32 ++++++++++ 12 files changed, 257 insertions(+), 48 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 22983a83..0c8d357c 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -15,9 +15,10 @@ int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); } -DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController) : +DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::SpiNorFlash& spiNorFlash) : systemTask{systemTask}, bleController{bleController}, + spiNorFlash{spiNorFlash}, characteristicDefinition{ { .uuid = (ble_uuid_t *) &packetCharacteristicUuid, @@ -104,6 +105,15 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24); NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); + for(int erased = 0; erased < applicationSize; erased += 0x1000) { + spiNorFlash.SectorErase(erased); + + auto p = spiNorFlash.ProgramFailed(); + auto e = spiNorFlash.EraseFailed(); + NRF_LOG_INFO("[DFU] Erasing sector %d - %d-%d", erased, p, e); + + } + uint8_t data[] {16, 1, 1}; SendNotification(connectionHandle, data, 3); state = States::Init; @@ -128,10 +138,15 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { case States::Data: { nbPacketReceived++; + + spiNorFlash.Write(bytesReceived, om->om_data, om->om_len); + bytesReceived += om->om_len; bleController.FirmwareUpdateCurrentBytes(bytesReceived); NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); + + if((nbPacketReceived % nbPacketsToNotify) == 0) { uint8_t data[5]{static_cast(Opcodes::PacketReceiptNotification), (uint8_t)(bytesReceived&0x000000FFu),(uint8_t)(bytesReceived>>8u), (uint8_t)(bytesReceived>>16u),(uint8_t)(bytesReceived>>24u) }; diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index f59ba2c9..1406d6ad 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -8,17 +8,22 @@ 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); + 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); private: Pinetime::System::SystemTask& systemTask; Pinetime::Controllers::Ble& bleController; + Pinetime::Drivers::SpiNorFlash& spiNorFlash; static constexpr uint16_t dfuServiceId {0x1530}; static constexpr uint16_t packetCharacteristicId {0x1532}; diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 1175022e..d2ee4801 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -24,12 +24,14 @@ using namespace Pinetime::Controllers; NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, DateTime& dateTimeController, - Pinetime::Controllers::NotificationManager& notificationManager) : + Pinetime::Controllers::NotificationManager& notificationManager, + Pinetime::Drivers::SpiNorFlash& spiNorFlash) : systemTask{systemTask}, bleController{bleController}, dateTimeController{dateTimeController}, notificationManager{notificationManager}, - dfuService{systemTask, bleController}, + spiNorFlash{spiNorFlash}, + dfuService{systemTask, bleController, spiNorFlash}, currentTimeClient{dateTimeController}, alertNotificationClient{systemTask, notificationManager} { diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index c4922bae..9f74be2b 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -8,12 +8,17 @@ #include namespace Pinetime { + namespace Drivers { + class SpiNorFlash; + } namespace Controllers { class DateTime; class NimbleController { public: - NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager); + NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, + DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager, + Pinetime::Drivers::SpiNorFlash& spiNorFlash); void Init(); void StartAdvertising(); int OnGAPEvent(ble_gap_event *event); @@ -34,6 +39,7 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; DateTime& dateTimeController; Pinetime::Controllers::NotificationManager& notificationManager; + Pinetime::Drivers::SpiNorFlash& spiNorFlash; Pinetime::Controllers::DfuService dfuService; DeviceInformationService deviceInformationService; diff --git a/src/DisplayApp/LittleVgl.cpp b/src/DisplayApp/LittleVgl.cpp index b1b894f7..7b6cda94 100644 --- a/src/DisplayApp/LittleVgl.cpp +++ b/src/DisplayApp/LittleVgl.cpp @@ -74,6 +74,9 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) { void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) { ulTaskNotifyTake(pdTRUE, 500); + // NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin + // which cannot be set/clear during a transfert. + // TODO refactore and remove duplicated code diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index c29a932a..022cade4 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -23,7 +23,7 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, spi{spi}, lcd{lcd}, spiNorFlash{spiNorFlash}, touchPanel{touchPanel}, lvgl{lvgl}, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager}, - nimbleController(*this, bleController,dateTimeController, notificationManager) { + nimbleController(*this, bleController,dateTimeController, notificationManager, spiNorFlash) { systemTaksMsgQueue = xQueueCreate(10, 1); } @@ -39,19 +39,17 @@ void SystemTask::Process(void *instance) { } void SystemTask::Work() { - watchdog.Setup(7); - watchdog.Start(); +// watchdog.Setup(7); +// watchdog.Start(); NRF_LOG_INFO("Last reset reason : %s", Pinetime::Drivers::Watchdog::ResetReasonToString(watchdog.ResetReason())); APP_GPIOTE_INIT(2); -/* BLE */ + spi.Init(); + spiNorFlash.Init(); nimbleController.Init(); nimbleController.StartAdvertising(); -/* /BLE*/ - - spi.Init(); lcd.Init(); - spiNorFlash.Init(); + touchPanel.Init(); batteryController.Init(); diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index 76490aed..ec3a5e94 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -5,15 +5,16 @@ using namespace Pinetime::Drivers; Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster{spiMaster}, pinCsn{pinCsn} { - + nrf_gpio_cfg_output(pinCsn); + nrf_gpio_pin_set(pinCsn); } bool Spi::Write(const uint8_t *data, size_t size) { return spiMaster.Write(pinCsn, data, size); } -bool Spi::Read(uint8_t *data, size_t size) { - return spiMaster.Read(pinCsn, data, size); +bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + return spiMaster.Read(pinCsn, cmd, cmdSize, data, dataSize); } void Spi::Sleep() { @@ -26,4 +27,8 @@ bool Spi::Init() { return true; } +bool Spi::WriteCmdAndBuffer(uint8_t *cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + return spiMaster.WriteCmdAndBuffer(pinCsn, cmd, cmdSize, data, dataSize); +} + diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index 7e155582..bee39af2 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -21,7 +21,8 @@ namespace Pinetime { bool Init(); bool Write(const uint8_t* data, size_t size); - bool Read(uint8_t* data, size_t size); + bool Read(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); + bool WriteCmdAndBuffer(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); void Sleep(); void Wakeup(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 7e5bb935..4d44a435 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -9,7 +9,8 @@ using namespace Pinetime::Drivers; SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters ¶ms) : spi{spi}, params{params} { - + mutex = xSemaphoreCreateBinary(); + ASSERT(mutex != NULL); } bool SpiMaster::Init() { @@ -67,6 +68,8 @@ bool SpiMaster::Init() { NRFX_IRQ_PRIORITY_SET(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn,2); NRFX_IRQ_ENABLE(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn); + + xSemaphoreGive(mutex); return true; } @@ -93,13 +96,17 @@ void SpiMaster::DisableWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_ch NRF_PPI->CH[ppi_channel].EEP = 0; NRF_PPI->CH[ppi_channel].TEP = 0; NRF_PPI->CHENSET = ppi_channel; + spiBaseAddress->EVENTS_END = 0; spim->INTENSET = (1<<6); spim->INTENSET = (1<<1); spim->INTENSET = (1<<19); } void SpiMaster::OnEndEvent() { - if(!busy) return; + if(currentBufferAddr == 0) { + asm("nop"); + return; + } auto s = currentBufferSize; if(s > 0) { @@ -112,7 +119,7 @@ void SpiMaster::OnEndEvent() { } else { uint8_t* buffer = nullptr; size_t size = 0; - busy = false; + if(taskToNotify != nullptr) { @@ -122,11 +129,14 @@ void SpiMaster::OnEndEvent() { } nrf_gpio_pin_set(this->pinCsn); + currentBufferAddr = 0; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(mutex, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } void SpiMaster::OnStartedEvent() { - if(!busy) return; } void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size) { @@ -139,7 +149,7 @@ void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile spiBaseAddress->EVENTS_END = 0; } -void SpiMaster::PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size) { +void SpiMaster::PrepareRx(const volatile uint32_t cmdAddress, const volatile size_t cmdSize, const volatile uint32_t bufferAddress, const volatile size_t size) { spiBaseAddress->TXD.PTR = 0; spiBaseAddress->TXD.MAXCNT = 0; spiBaseAddress->TXD.LIST = 0; @@ -152,10 +162,10 @@ void SpiMaster::PrepareRx(const volatile uint32_t bufferAddress, const volatile bool SpiMaster::Write(uint8_t pinCsn, const uint8_t *data, size_t size) { if(data == nullptr) return false; + auto ok = xSemaphoreTake(mutex, portMAX_DELAY); + ASSERT(ok == true); taskToNotify = xTaskGetCurrentTaskHandle(); - while(busy) { - asm("nop"); - } + this->pinCsn = pinCsn; @@ -169,7 +179,6 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t *data, size_t size) { currentBufferAddr = (uint32_t)data; currentBufferSize = size; - busy = true; auto currentSize = std::min((size_t)255, (size_t)currentBufferSize); PrepareTx(currentBufferAddr, currentSize); @@ -179,34 +188,42 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t *data, size_t size) { if(size == 1) { while (spiBaseAddress->EVENTS_END == 0); - busy = false; + nrf_gpio_pin_set(this->pinCsn); + currentBufferAddr = 0; + xSemaphoreGive(mutex); } return true; } -bool SpiMaster::Read(uint8_t pinCsn, uint8_t *data, size_t size) { - while(busy) { - asm("nop"); - } +bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + xSemaphoreTake(mutex, portMAX_DELAY); + taskToNotify = nullptr; this->pinCsn = pinCsn; - SetupWorkaroundForFtpan58(spiBaseAddress, 0,0); + DisableWorkaroundForFtpan58(spiBaseAddress, 0,0); + spiBaseAddress->INTENCLR = (1<<6); + spiBaseAddress->INTENCLR = (1<<1); + spiBaseAddress->INTENCLR = (1<<19); nrf_gpio_pin_clear(this->pinCsn); + currentBufferAddr = 0; currentBufferSize = 0; - busy = true; - PrepareRx((uint32_t)data, size); + PrepareTx((uint32_t)cmd, cmdSize); + spiBaseAddress->TASKS_START = 1; + while (spiBaseAddress->EVENTS_END == 0); + + PrepareRx((uint32_t)cmd, cmdSize, (uint32_t)data, dataSize); spiBaseAddress->TASKS_START = 1; while (spiBaseAddress->EVENTS_END == 0); nrf_gpio_pin_set(this->pinCsn); - busy = false; + xSemaphoreGive(mutex); return true; } @@ -225,5 +242,37 @@ void SpiMaster::Wakeup() { Init(); } +bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, uint8_t *cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + xSemaphoreTake(mutex, portMAX_DELAY); + + taskToNotify = nullptr; + + this->pinCsn = pinCsn; + DisableWorkaroundForFtpan58(spiBaseAddress, 0,0); + spiBaseAddress->INTENCLR = (1<<6); + spiBaseAddress->INTENCLR = (1<<1); + spiBaseAddress->INTENCLR = (1<<19); + + nrf_gpio_pin_clear(this->pinCsn); + + + currentBufferAddr = 0; + currentBufferSize = 0; + + PrepareTx((uint32_t)cmd, cmdSize); + spiBaseAddress->TASKS_START = 1; + while (spiBaseAddress->EVENTS_END == 0); + + PrepareTx((uint32_t)data, dataSize); + spiBaseAddress->TASKS_START = 1; + + while (spiBaseAddress->EVENTS_END == 0); + nrf_gpio_pin_set(this->pinCsn); + + xSemaphoreGive(mutex); + + return true; +} + diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 24b39b97..7b35dfc8 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "BufferProvider.h" namespace Pinetime { @@ -32,7 +33,9 @@ namespace Pinetime { bool Init(); bool Write(uint8_t pinCsn, const uint8_t* data, size_t size); - bool Read(uint8_t pinCsn, uint8_t* data, size_t size); + bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); + + bool WriteCmdAndBuffer(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); void OnStartedEvent(); void OnEndEvent(); @@ -44,7 +47,7 @@ namespace Pinetime { void SetupWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void DisableWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); - void PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size); + void PrepareRx(const volatile uint32_t cmdAddress, const volatile size_t cmdSize, const volatile uint32_t bufferAddress, const volatile size_t size); NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; @@ -52,10 +55,12 @@ namespace Pinetime { SpiMaster::SpiModule spi; SpiMaster::Parameters params; - volatile bool busy = false; +// volatile bool busy = false; volatile uint32_t currentBufferAddr = 0; volatile size_t currentBufferSize = 0; volatile TaskHandle_t taskToNotify; + + SemaphoreHandle_t mutex; }; } } diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp index d19548ee..8fbb53a1 100644 --- a/src/drivers/SpiNorFlash.cpp +++ b/src/drivers/SpiNorFlash.cpp @@ -11,16 +11,8 @@ SpiNorFlash::SpiNorFlash(Spi& spi) : spi{spi} { } void SpiNorFlash::Init() { - uint8_t cmd = 0x9F; - spi.Write(&cmd, 1); - - uint8_t data[3]; - data[0] = 0; - data[1] = 0; - data[2] = 0; - spi.Read(data, 3); - - NRF_LOG_INFO("Manufacturer : %d, Device : %d", data[0], (data[1] + (data[2]<<8))); + auto id = ReadIdentificaion(); + NRF_LOG_INFO("[SPI FLASH] Manufacturer : %d, Memory type : %d, memory density : %d", id.manufacturer, id.type, id.density); } void SpiNorFlash::Uninit() { @@ -34,3 +26,99 @@ void SpiNorFlash::Sleep() { void SpiNorFlash::Wakeup() { } + +SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() { + auto cmd = static_cast(Commands::ReadIdentification); + Identification identification; + spi.Read(&cmd, 1, reinterpret_cast(&identification), sizeof(Identification)); + return identification; +} + +uint8_t SpiNorFlash::ReadStatusRegister() { + auto cmd = static_cast(Commands::ReadStatusRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +bool SpiNorFlash::WriteInProgress() { + return (ReadStatusRegister() & 0x01u) == 0x01u; +} + +bool SpiNorFlash::WriteEnabled() { + return (ReadStatusRegister() & 0x02u) == 0x02u; +} + +uint8_t SpiNorFlash::ReadConfigurationRegister() { + auto cmd = static_cast(Commands::ReadConfigurationRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +void SpiNorFlash::Read(uint32_t address, uint8_t *buffer, size_t size) { + static constexpr uint8_t cmdSize = 4; + uint8_t cmd[cmdSize] = { static_cast(Commands::Read), (uint8_t)(address >> 16U), (uint8_t)(address >> 8U), + (uint8_t)address }; + spi.Read(reinterpret_cast(&cmd), cmdSize, buffer, size); +} + +void SpiNorFlash::WriteEnable() { + auto cmd = static_cast(Commands::WriteEnable); + spi.Read(&cmd, sizeof(cmd), nullptr, 0); +} + +void SpiNorFlash::SectorErase(uint32_t sectorAddress) { + static constexpr uint8_t cmdSize = 4; + uint8_t cmd[cmdSize] = { static_cast(Commands::SectorErase), (uint8_t)(sectorAddress >> 16U), (uint8_t)(sectorAddress >> 8U), + (uint8_t)sectorAddress }; + + WriteEnable(); + while(!WriteEnabled()) vTaskDelay(1); + + spi.Read(reinterpret_cast(&cmd), cmdSize, nullptr, 0); + + while(WriteInProgress()) vTaskDelay(1); +} + +uint8_t SpiNorFlash::ReadSecurityRegister() { + auto cmd = static_cast(Commands::ReadSecurityRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +bool SpiNorFlash::ProgramFailed() { + return (ReadSecurityRegister() & 0x20u) == 0x20u; +} + +bool SpiNorFlash::EraseFailed() { + return (ReadSecurityRegister() & 0x40u) == 0x40u; +} + +void SpiNorFlash::Write(uint32_t address, uint8_t *buffer, size_t size) { + static constexpr uint8_t cmdSize = 4; + + size_t len = size; + uint32_t addr = address; + uint8_t* b = buffer; + while(len > 0) { + uint32_t pageLimit = (addr & ~(pageSize - 1u)) + pageSize; + uint32_t toWrite = pageLimit - addr > len ? len : pageLimit - addr; + + uint8_t cmd[cmdSize] = { static_cast(Commands::PageProgram), (uint8_t)(addr >> 16U), (uint8_t)(addr >> 8U), + (uint8_t)addr }; + + WriteEnable(); + while(!WriteEnabled()) vTaskDelay(1); + + spi.WriteCmdAndBuffer(cmd, cmdSize, b, toWrite); + + while(WriteInProgress()) vTaskDelay(1); + + addr += toWrite; + b += toWrite; + len -= toWrite; + } + +} diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h index 839a1c2a..b5f19202 100644 --- a/src/drivers/SpiNorFlash.h +++ b/src/drivers/SpiNorFlash.h @@ -12,6 +12,26 @@ namespace Pinetime { SpiNorFlash(SpiNorFlash&&) = delete; SpiNorFlash& operator=(SpiNorFlash&&) = delete; + typedef struct __attribute__((packed)) { + uint8_t manufacturer = 0; + uint8_t type = 0; + uint8_t density = 0; + } Identification; + + Identification ReadIdentificaion(); + uint8_t ReadStatusRegister(); + bool WriteInProgress(); + bool WriteEnabled(); + uint8_t ReadConfigurationRegister(); + void Read(uint32_t address, uint8_t* buffer, size_t size); + void Write(uint32_t address, uint8_t *buffer, size_t size); + void WriteEnable(); + void SectorErase(uint32_t sectorAddress); + uint8_t ReadSecurityRegister(); + bool ProgramFailed(); + bool EraseFailed(); + + void Init(); void Uninit(); @@ -19,6 +39,18 @@ namespace Pinetime { void Sleep(); void Wakeup(); private: + enum class Commands : uint8_t { + PageProgram = 0x02, + Read = 0x03, + ReadStatusRegister = 0x05, + WriteEnable = 0x06, + ReadConfigurationRegister = 0x15, + SectorErase = 0x20, + ReadSecurityRegister = 0x2B, + ReadIdentification = 0x9F, + }; + static constexpr uint16_t pageSize = 256; + Spi& spi; }; -- cgit v1.2.3 From ce328636935dbc580aad1245fdaff54d6ba947a3 Mon Sep 17 00:00:00 2001 From: JF Date: Wed, 20 May 2020 18:39:25 +0200 Subject: Fix offset issues in OTA procedure. CRC verification : work in progress (not fully working for now). --- src/Components/Ble/DfuService.cpp | 67 +++++++++++++++++++++++++++++++++++---- src/Components/Ble/DfuService.h | 10 +++++- 2 files changed, 70 insertions(+), 7 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 0c8d357c..e7b4c5f4 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "DfuService.h" using namespace Pinetime::Controllers; @@ -103,15 +104,17 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24); bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24); + bleController.FirmwareUpdateTotalBytes(applicationSize); NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); for(int erased = 0; erased < applicationSize; erased += 0x1000) { - spiNorFlash.SectorErase(erased); +#if 1 + spiNorFlash.SectorErase(writeOffset + erased); auto p = spiNorFlash.ProgramFailed(); auto e = spiNorFlash.EraseFailed(); NRF_LOG_INFO("[DFU] Erasing sector %d - %d-%d", erased, p, e); - +#endif } uint8_t data[] {16, 1, 1}; @@ -130,7 +133,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { } uint16_t crc = om->om_data[10 + (softdeviceArrayLength*2)] + (om->om_data[10 + (softdeviceArrayLength*2)] << 8); - NRF_LOG_INFO("[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %d", + NRF_LOG_INFO("[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u", deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], crc); return 0; @@ -138,8 +141,21 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { case States::Data: { nbPacketReceived++; + auto offset = ((nbPacketReceived-1) % nbPacketsToNotify)*20; + std::memcpy(tempBuffer + offset, om->om_data, om->om_len); + if(firstCrc) { + tempCrc = ComputeCrc(om->om_data, om->om_len, NULL); + firstCrc = false; + } + else + tempCrc = ComputeCrc(om->om_data, om->om_len, &tempCrc); + + if(nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { +#if 1 + spiNorFlash.Write(writeOffset + ((nbPacketReceived-nbPacketsToNotify)*20), tempBuffer, 200); +#endif + } - spiNorFlash.Write(bytesReceived, om->om_data, om->om_len); bytesReceived += om->om_len; bleController.FirmwareUpdateCurrentBytes(bytesReceived); @@ -157,9 +173,11 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; - NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); + NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received! CRC = %u", tempCrc); SendNotification(connectionHandle, data, 3); state = States::Validate; + + Validate(); } } return 0; @@ -189,7 +207,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Start DFU, mode = Application"); state = States::Start; bleController.StartFirmwareUpdate(); - bleController.FirmwareUpdateTotalBytes(175280); + bleController.FirmwareUpdateTotalBytes(0xffffffffu); bleController.FirmwareUpdateCurrentBytes(0); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateStarted); return 0; @@ -260,3 +278,40 @@ void DfuService::SendNotification(uint16_t connectionHandle, const uint8_t *data auto ret = ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); ASSERT(ret == 0); } + +uint16_t DfuService::ComputeCrc(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc) +{ + uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; + + for (uint32_t i = 0; i < size; i++) + { + crc = (uint8_t)(crc >> 8) | (crc << 8); + crc ^= p_data[i]; + crc ^= (uint8_t)(crc & 0xFF) >> 4; + crc ^= (crc << 8) << 4; + crc ^= ((crc & 0xFF) << 4) << 1; + } + + return crc; +} + +void DfuService::Validate() { + uint32_t chunkSize = 200; + int currentOffset = 0; + uint16_t crc = 0; + + bool first = true; + while(currentOffset < applicationSize) { + uint32_t readSize = (applicationSize - currentOffset) > chunkSize ? chunkSize : (applicationSize - currentOffset); + + spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, chunkSize); + if(first) { + crc = ComputeCrc(tempBuffer, chunkSize, NULL); + first = false; + } + else + crc = ComputeCrc(tempBuffer, chunkSize, &crc); + currentOffset += readSize; + } + NRF_LOG_INFO("CRC : %u", crc); +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 1406d6ad..e22e09f0 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -89,15 +89,23 @@ namespace Pinetime { uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; uint32_t bytesReceived = 0; + uint32_t writeOffset = 0; //0x40000; uint32_t softdeviceSize = 0; uint32_t bootloaderSize = 0; - uint32_t applicationSize = 0; + uint32_t applicationSize = 115200; int SendDfuRevision(os_mbuf *om) const; void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om); + + uint8_t tempBuffer[200]; + uint16_t ComputeCrc(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc); + + void Validate(); + bool firstCrc = true; + uint16_t tempCrc = 0; }; } } \ No newline at end of file -- cgit v1.2.3 From 3cc76d7673f6a3b8b5253d04b358b440e550fdb4 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 24 May 2020 09:15:59 +0200 Subject: Working demo of OTA using MCUBoot https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.4 --- gcc_nrf52.ld | 2 +- src/Components/Ble/DfuService.cpp | 33 ++++++++++++++++++++++++++++----- src/Components/Ble/DfuService.h | 9 ++++++--- src/SystemTask/SystemTask.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) (limited to 'src/Components/Ble') diff --git a/gcc_nrf52.ld b/gcc_nrf52.ld index b849ea2c..0746f491 100644 --- a/gcc_nrf52.ld +++ b/gcc_nrf52.ld @@ -5,7 +5,7 @@ GROUP(-lgcc -lc -lnosys) MEMORY { - FLASH (rx) : ORIGIN = 0x00000, LENGTH = 0x80000 + FLASH (rx) : ORIGIN = 0x08020, LENGTH = 0x78000 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 } diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index e7b4c5f4..de525321 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -107,7 +107,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { bleController.FirmwareUpdateTotalBytes(applicationSize); NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); - for(int erased = 0; erased < applicationSize; erased += 0x1000) { + for(int erased = 0; erased < maxImageSize; erased += 0x1000) { #if 1 spiNorFlash.SectorErase(writeOffset + erased); @@ -159,7 +159,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { bytesReceived += om->om_len; bleController.FirmwareUpdateCurrentBytes(bytesReceived); - NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); + //NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); @@ -170,6 +170,16 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { SendNotification(connectionHandle, data, 5); } if(bytesReceived == applicationSize) { + if((nbPacketReceived % nbPacketsToNotify) != 0) { + auto remaningPacket = nbPacketReceived % nbPacketsToNotify; + uint32_t spiOffset = writeOffset + ((nbPacketReceived-remaningPacket)*20); + + spiNorFlash.Write(writeOffset + ((nbPacketReceived-remaningPacket)*20), tempBuffer, remaningPacket * 20); + } + if(applicationSize < maxImageSize) { + WriteMagicNumber(); + } + uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; @@ -304,14 +314,27 @@ void DfuService::Validate() { while(currentOffset < applicationSize) { uint32_t readSize = (applicationSize - currentOffset) > chunkSize ? chunkSize : (applicationSize - currentOffset); - spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, chunkSize); + spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, readSize); if(first) { - crc = ComputeCrc(tempBuffer, chunkSize, NULL); + crc = ComputeCrc(tempBuffer, readSize, NULL); first = false; } else - crc = ComputeCrc(tempBuffer, chunkSize, &crc); + crc = ComputeCrc(tempBuffer, readSize, &crc); currentOffset += readSize; } + NRF_LOG_INFO("CRC : %u", crc); } + +void DfuService::WriteMagicNumber() { + uint32_t magic[4] = { + 0xf395c277, + 0x7fefd260, + 0x0f505235, + 0x8079b62c, + }; + + uint32_t offset = writeOffset + (maxImageSize - (4 * sizeof(uint32_t))); + spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index e22e09f0..c8351ede 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -18,6 +18,7 @@ namespace Pinetime { DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::SpiNorFlash& spiNorFlash); void Init(); + void Validate(); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); private: @@ -89,11 +90,12 @@ namespace Pinetime { uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; uint32_t bytesReceived = 0; - uint32_t writeOffset = 0; //0x40000; + uint32_t writeOffset = 0x40000; uint32_t softdeviceSize = 0; uint32_t bootloaderSize = 0; - uint32_t applicationSize = 115200; + uint32_t applicationSize = 0; + static constexpr uint32_t maxImageSize = 475136; int SendDfuRevision(os_mbuf *om) const; void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); @@ -103,9 +105,10 @@ namespace Pinetime { uint8_t tempBuffer[200]; uint16_t ComputeCrc(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc); - void Validate(); bool firstCrc = true; uint16_t tempCrc = 0; + + void WriteMagicNumber(); }; } } \ No newline at end of file diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 022cade4..021bac3d 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -38,6 +38,27 @@ void SystemTask::Process(void *instance) { app->Work(); } +static inline void nrf52_wait_for_flash_ready(void) +{ + while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {;} +} + +void nrf52_nvmc_write_word(uint32_t address, uint32_t value) { + // Enable write. + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen; + __ISB(); + __DSB(); + + // Write word + *(uint32_t*)address = value; + nrf52_wait_for_flash_ready(); + + // Disable write + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren; + __ISB(); + __DSB(); +} + void SystemTask::Work() { // watchdog.Setup(7); // watchdog.Start(); @@ -46,6 +67,14 @@ void SystemTask::Work() { spi.Init(); spiNorFlash.Init(); + + // TODO write magic only if it's not already 1 + nrf52_nvmc_write_word(0x7BFE8, 1); + + uint32_t* magicptr = reinterpret_cast(0x7BFE8); + uint32_t magic = *magicptr; + NRF_LOG_INFO("MAGIC : %d", magic); + nimbleController.Init(); nimbleController.StartAdvertising(); lcd.Init(); -- cgit v1.2.3 From dca559aad5a5020ae0d5c1bec08bbf5030e0d718 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 1 Jun 2020 09:22:54 +0200 Subject: Improve DFU procedure : - correctly write all bytes to flash - check CRC - Fix bug in notification : they cannot be sent from the control point handler (because it seems you cannot send a notification and a write acknowledge at the same time) using a timer (quick'n'dirty implementation to be improved) - Improve dfu screen - Reset if dfu image is correctly copied into flash and crc is ok. --- src/CMakeLists.txt | 2 + src/Components/Ble/BleController.h | 4 + src/Components/Ble/DfuService.cpp | 269 +++++++++++++++++------------- src/Components/Ble/DfuService.h | 69 +++++--- src/DisplayApp/Screens/FirmwareUpdate.cpp | 45 +++++ src/DisplayApp/Screens/FirmwareUpdate.h | 17 +- src/SystemTask/SystemTask.cpp | 1 + 7 files changed, 265 insertions(+), 142 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c0a46ed0..c37a05a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -355,6 +355,7 @@ list(APPEND SOURCE_FILES Components/Ble/DfuService.cpp Components/Ble/CurrentTimeService.cpp Components/Ble/AlertNotificationService.cpp + Components/Ble/DfuImage.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -408,6 +409,7 @@ set(INCLUDE_FILES Components/Ble/CurrentTimeClient.h Components/Ble/AlertNotificationClient.h Components/Ble/DfuService.h + Components/Ble/DfuImage.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/Components/Ble/BleController.h b/src/Components/Ble/BleController.h index 65a5ef8f..c47e65b6 100644 --- a/src/Components/Ble/BleController.h +++ b/src/Components/Ble/BleController.h @@ -7,6 +7,7 @@ namespace Pinetime { namespace Controllers { class Ble { public: + enum class FirmwareUpdateStates {Idle, Running, Validated, Error}; Ble() = default; bool IsConnected() const {return isConnected;} @@ -17,15 +18,18 @@ namespace Pinetime { void StopFirmwareUpdate(); void FirmwareUpdateTotalBytes(uint32_t totalBytes); void FirmwareUpdateCurrentBytes(uint32_t currentBytes); + void State(FirmwareUpdateStates state) { firmwareUpdateState = state; } bool IsFirmwareUpdating() const { return isFirmwareUpdating; } uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } + FirmwareUpdateStates State() const { return firmwareUpdateState; } private: bool isConnected = false; bool isFirmwareUpdating = false; uint32_t firmwareUpdateTotalBytes = 0; uint32_t firmwareUpdateCurrentBytes = 0; + FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle; }; } diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index de525321..0d67d848 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -12,11 +12,17 @@ constexpr ble_uuid128_t DfuService::packetCharacteristicUuid; int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - auto dfuService = static_cast(arg); + auto dfuService = static_cast(arg); return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); } -DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::SpiNorFlash& spiNorFlash) : +void NotificationTimerCallback( TimerHandle_t xTimer ) { + auto dfuService = static_cast(pvTimerGetTimerID( xTimer )); + dfuService->OnNotificationTimer(); +} + +DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, + Pinetime::Drivers::SpiNorFlash &spiNorFlash) : systemTask{systemTask}, bleController{bleController}, spiNorFlash{spiNorFlash}, @@ -44,11 +50,11 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Contr }, { - 0 + 0 } }, - serviceDefinition { + serviceDefinition{ { /* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, @@ -58,10 +64,8 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Contr { 0 }, - } - - { - + } { + notificationTimer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback); } void DfuService::Init() { @@ -71,20 +75,23 @@ void DfuService::Init() { int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { - ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&packetCharacteristicUuid, nullptr, &packetCharacteristicHandle); - ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle); - ble_gatts_find_chr((ble_uuid_t*)&serviceUuid, (ble_uuid_t*)&revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle); + ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr, + &packetCharacteristicHandle); + ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &controlPointCharacteristicUuid, nullptr, + &controlPointCharacteristicHandle); + ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &revisionCharacteristicUuid, nullptr, + &revisionCharacteristicHandle); - if(attributeHandle == packetCharacteristicHandle) { - if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) + if (attributeHandle == packetCharacteristicHandle) { + if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) return WritePacketHandler(connectionHandle, context->om); else return 0; - } else if(attributeHandle == controlPointCharacteristicHandle) { - if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) - return ControlPointHandler(connectionHandle, context->om); + } else if (attributeHandle == controlPointCharacteristicHandle) { + if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) + return ControlPointHandler(connectionHandle, context->om); else return 0; - } else if(attributeHandle == revisionCharacteristicHandle) { - if(context->op == BLE_GATT_ACCESS_OP_READ_CHR) + } else if (attributeHandle == revisionCharacteristicHandle) { + if (context->op == BLE_GATT_ACCESS_OP_READ_CHR) return SendDfuRevision(context->om); else return 0; } else { @@ -99,25 +106,22 @@ int DfuService::SendDfuRevision(os_mbuf *om) const { } int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { - switch(state) { + switch (state) { case States::Start: { softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24); bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24); bleController.FirmwareUpdateTotalBytes(applicationSize); - NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); + NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, + bootloaderSize, applicationSize); - for(int erased = 0; erased < maxImageSize; erased += 0x1000) { + for (int erased = 0; erased < maxImageSize; erased += 0x1000) { #if 1 spiNorFlash.SectorErase(writeOffset + erased); - - auto p = spiNorFlash.ProgramFailed(); - auto e = spiNorFlash.EraseFailed(); - NRF_LOG_INFO("[DFU] Erasing sector %d - %d-%d", erased, p, e); #endif } - uint8_t data[] {16, 1, 1}; + uint8_t data[]{16, 1, 1}; SendNotification(connectionHandle, data, 3); state = States::Init; } @@ -125,34 +129,36 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { case States::Init: { uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8); uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8); - uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); + uint32_t applicationVersion = + om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8); uint16_t sd[softdeviceArrayLength]; - for(int i = 0; i < softdeviceArrayLength; i++) { - sd[i] = om->om_data[10 + (i*2)] + (om->om_data[(i*2)+1] << 8); + for (int i = 0; i < softdeviceArrayLength; i++) { + sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8); } - uint16_t crc = om->om_data[10 + (softdeviceArrayLength*2)] + (om->om_data[10 + (softdeviceArrayLength*2)] << 8); + expectedCrc = + om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8); - NRF_LOG_INFO("[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u", - deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], crc); + NRF_LOG_INFO( + "[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u", + deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], expectedCrc); return 0; } case States::Data: { nbPacketReceived++; - auto offset = ((nbPacketReceived-1) % nbPacketsToNotify)*20; + auto offset = ((nbPacketReceived - 1) % nbPacketsToNotify) * 20; std::memcpy(tempBuffer + offset, om->om_data, om->om_len); - if(firstCrc) { - tempCrc = ComputeCrc(om->om_data, om->om_len, NULL); - firstCrc = false; - } - else - tempCrc = ComputeCrc(om->om_data, om->om_len, &tempCrc); + if (firstCrc) { + tempCrc = ComputeCrc(om->om_data, om->om_len, NULL); + firstCrc = false; + } else + tempCrc = ComputeCrc(om->om_data, om->om_len, &tempCrc); - if(nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { + if (nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { #if 1 - spiNorFlash.Write(writeOffset + ((nbPacketReceived-nbPacketsToNotify)*20), tempBuffer, 200); + spiNorFlash.Write(writeOffset + ((nbPacketReceived - nbPacketsToNotify) * 20), tempBuffer, 200); #endif } @@ -163,31 +169,30 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { - if((nbPacketReceived % nbPacketsToNotify) == 0) { + if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) { uint8_t data[5]{static_cast(Opcodes::PacketReceiptNotification), - (uint8_t)(bytesReceived&0x000000FFu),(uint8_t)(bytesReceived>>8u), (uint8_t)(bytesReceived>>16u),(uint8_t)(bytesReceived>>24u) }; - NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received",bytesReceived); + (uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u), + (uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)}; + NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived); SendNotification(connectionHandle, data, 5); } - if(bytesReceived == applicationSize) { - if((nbPacketReceived % nbPacketsToNotify) != 0) { - auto remaningPacket = nbPacketReceived % nbPacketsToNotify; - uint32_t spiOffset = writeOffset + ((nbPacketReceived-remaningPacket)*20); + if (bytesReceived == applicationSize) { + if ((nbPacketReceived % nbPacketsToNotify) != 0) { + auto remaningPacket = nbPacketReceived % nbPacketsToNotify; + uint32_t spiOffset = writeOffset + ((nbPacketReceived - remaningPacket) * 20); + + spiNorFlash.Write(writeOffset + ((nbPacketReceived - remaningPacket) * 20), tempBuffer, remaningPacket * 20); + } - spiNorFlash.Write(writeOffset + ((nbPacketReceived-remaningPacket)*20), tempBuffer, remaningPacket * 20); - } - if(applicationSize < maxImageSize) { - WriteMagicNumber(); - } + if (applicationSize < maxImageSize) + WriteMagicNumber(); uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; - NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received! CRC = %u", tempCrc); + NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received! CRC = %u -- %d", tempCrc, connectionHandle); SendNotification(connectionHandle, data, 3); state = States::Validate; - - Validate(); } } return 0; @@ -202,21 +207,22 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { auto opcode = static_cast(om->om_data[0]); NRF_LOG_INFO("[DFU] -> ControlPointHandler"); - switch(opcode) { + switch (opcode) { case Opcodes::StartDFU: { - if(state != States::Idle && state != States::Start) { + if (state != States::Idle && state != States::Start) { NRF_LOG_INFO("[DFU] -> Start DFU requested, but we are not in Idle state"); return 0; } - if(state == States::Start) { + if (state == States::Start) { NRF_LOG_INFO("[DFU] -> Start DFU requested, but we are already in Start state"); return 0; } auto imageType = static_cast(om->om_data[1]); - if(imageType == ImageTypes::Application) { + if (imageType == ImageTypes::Application) { NRF_LOG_INFO("[DFU] -> Start DFU, mode = Application"); state = States::Start; bleController.StartFirmwareUpdate(); + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Running); bleController.FirmwareUpdateTotalBytes(0xffffffffu); bleController.FirmwareUpdateCurrentBytes(0); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateStarted); @@ -236,11 +242,12 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete"); if (isInitComplete) { - uint8_t data[3]{static_cast(Opcodes::Response), - static_cast(Opcodes::InitDFUParameters), - (isInitComplete ? uint8_t{1} : uint8_t{0})}; - NRF_LOG_INFO("SEND NOTIF : %d %d %d", data[0], data[1], data[2]); - SendNotification(connectionHandle, data, 3); + notificationBuffer[0] = static_cast(Opcodes::Response); + notificationBuffer[1] = static_cast(Opcodes::InitDFUParameters); + notificationBuffer[2] = (isInitComplete ? uint8_t{1} : uint8_t{0}); + notificationSize = 3; + notificatonConnectionHandle = connectionHandle; + xTimerStart(notificationTimer, 0); return 0; } } @@ -250,7 +257,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Receive Packet Notification Request, nb packet = %d", nbPacketsToNotify); return 0; case Opcodes::ReceiveFirmwareImage: - if(state != States::Init) { + if (state != States::Init) { NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start Init"); return 0; } @@ -258,20 +265,36 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { state = States::Data; return 0; case Opcodes::ValidateFirmware: { - if(state != States::Validate) { + if (state != States::Validate) { NRF_LOG_INFO("[DFU] -> Validate firmware image requested, but we are not in Data state"); return 0; } - NRF_LOG_INFO("[DFU] -> Validate firmware"); - state = States::Validated; - uint8_t data[3]{static_cast(Opcodes::Response), - static_cast(Opcodes::ValidateFirmware), - static_cast(ErrorCodes::NoError)}; - SendNotification(connectionHandle, data, 3); + + NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle); + + if(Validate()){ + state = States::Validated; + + notificationBuffer[0] = static_cast(Opcodes::Response); + notificationBuffer[1] = static_cast(Opcodes::ValidateFirmware); + notificationBuffer[2] = static_cast(ErrorCodes::NoError); + notificationSize = 3; + notificatonConnectionHandle = connectionHandle; + xTimerStart(notificationTimer, 0); + + } else { + notificationBuffer[0] = static_cast(Opcodes::Response); + notificationBuffer[1] = static_cast(Opcodes::ValidateFirmware); + notificationBuffer[2] = static_cast(ErrorCodes::CrcError); + notificationSize = 3; + notificatonConnectionHandle = connectionHandle; + xTimerStart(notificationTimer, 0); + } + return 0; } case Opcodes::ActivateImageAndReset: - if(state != States::Validated) { + if (state != States::Validated) { NRF_LOG_INFO("[DFU] -> Activate image and reset requested, but we are not in Validated state"); return 0; } @@ -279,7 +302,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { bleController.StopFirmwareUpdate(); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished); return 0; - default: return 0; + default: + return 0; } } @@ -289,52 +313,65 @@ void DfuService::SendNotification(uint16_t connectionHandle, const uint8_t *data ASSERT(ret == 0); } -uint16_t DfuService::ComputeCrc(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc) -{ - uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; - - for (uint32_t i = 0; i < size; i++) - { - crc = (uint8_t)(crc >> 8) | (crc << 8); - crc ^= p_data[i]; - crc ^= (uint8_t)(crc & 0xFF) >> 4; - crc ^= (crc << 8) << 4; - crc ^= ((crc & 0xFF) << 4) << 1; - } - - return crc; -} +uint16_t DfuService::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) { + uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; -void DfuService::Validate() { - uint32_t chunkSize = 200; - int currentOffset = 0; - uint16_t crc = 0; + for (uint32_t i = 0; i < size; i++) { + crc = (uint8_t) (crc >> 8) | (crc << 8); + crc ^= p_data[i]; + crc ^= (uint8_t) (crc & 0xFF) >> 4; + crc ^= (crc << 8) << 4; + crc ^= ((crc & 0xFF) << 4) << 1; + } - bool first = true; - while(currentOffset < applicationSize) { - uint32_t readSize = (applicationSize - currentOffset) > chunkSize ? chunkSize : (applicationSize - currentOffset); + return crc; +} - spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, readSize); - if(first) { - crc = ComputeCrc(tempBuffer, readSize, NULL); - first = false; - } - else - crc = ComputeCrc(tempBuffer, readSize, &crc); - currentOffset += readSize; - } +bool DfuService::Validate() { + uint32_t chunkSize = 200; + int currentOffset = 0; + uint16_t crc = 0; + + bool first = true; + while (currentOffset < applicationSize) { + uint32_t readSize = (applicationSize - currentOffset) > chunkSize ? chunkSize : (applicationSize - currentOffset); + + spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, readSize); + if (first) { + crc = ComputeCrc(tempBuffer, readSize, NULL); + first = false; + } else + crc = ComputeCrc(tempBuffer, readSize, &crc); + currentOffset += readSize; + } - NRF_LOG_INFO("CRC : %u", crc); + NRF_LOG_INFO("Expected CRC : %u - Processed CRC : %u", expectedCrc, crc); + bool crcOk = (crc == expectedCrc); + if (crcOk) { + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); + NRF_LOG_INFO("Image OK"); + } else { + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); + NRF_LOG_INFO("Image Error : bad CRC"); + } + return crcOk; } void DfuService::WriteMagicNumber() { - uint32_t magic[4] = { - 0xf395c277, - 0x7fefd260, - 0x0f505235, - 0x8079b62c, - }; - - uint32_t offset = writeOffset + (maxImageSize - (4 * sizeof(uint32_t))); - spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); + uint32_t magic[4] = { + 0xf395c277, + 0x7fefd260, + 0x0f505235, + 0x8079b62c, + }; + + uint32_t offset = writeOffset + (maxImageSize - (4 * sizeof(uint32_t))); + spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); +} + +void DfuService::OnNotificationTimer() { + if(notificationSize > 0) { + SendNotification(notificatonConnectionHandle, notificationBuffer, notificationSize); + notificationSize = 0; + } } diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index c8351ede..3de17f9f 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -1,4 +1,5 @@ #pragma once + #include #include @@ -13,46 +14,51 @@ namespace Pinetime { } namespace Controllers { class Ble; + class DfuService { public: - DfuService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, - Pinetime::Drivers::SpiNorFlash& spiNorFlash); + DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, + Pinetime::Drivers::SpiNorFlash &spiNorFlash); + void Init(); - void Validate(); + + bool Validate(); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); + void OnNotificationTimer(); + private: - Pinetime::System::SystemTask& systemTask; - Pinetime::Controllers::Ble& bleController; - Pinetime::Drivers::SpiNorFlash& spiNorFlash; + Pinetime::System::SystemTask &systemTask; + Pinetime::Controllers::Ble &bleController; + Pinetime::Drivers::SpiNorFlash &spiNorFlash; - static constexpr uint16_t dfuServiceId {0x1530}; - static constexpr uint16_t packetCharacteristicId {0x1532}; - static constexpr uint16_t controlPointCharacteristicId {0x1531}; - static constexpr uint16_t revisionCharacteristicId {0x1534}; + 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}; + uint16_t revision{0x0008}; - static constexpr ble_uuid128_t serviceUuid { - .u { .type = BLE_UUID_TYPE_128}, + 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}, + 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}, + 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}, + 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} }; @@ -63,7 +69,9 @@ namespace Pinetime { uint16_t controlPointCharacteristicHandle; uint16_t revisionCharacteristicHandle; - enum class States : uint8_t {Idle, Init, Start, Data, Validate, Validated}; + enum class States : uint8_t { + Idle, Init, Start, Data, Validate, Validated + }; States state = States::Idle; enum class ImageTypes : uint8_t { @@ -85,7 +93,14 @@ namespace Pinetime { PacketReceiptNotification = 0x11 }; - enum class ErrorCodes { NoError = 0x01}; + enum class ErrorCodes { + NoError = 0x01, + InvalidState = 0x02, + NotSupported = 0x03, + DataSizeExceedsLimits = 0x04, + CrcError = 0x05, + OperationFailed = 0x06 + }; uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; @@ -96,19 +111,29 @@ namespace Pinetime { uint32_t bootloaderSize = 0; uint32_t applicationSize = 0; static constexpr uint32_t maxImageSize = 475136; + uint16_t expectedCrc = 0; int SendDfuRevision(os_mbuf *om) const; + void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); + int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); + int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om); uint8_t tempBuffer[200]; - uint16_t ComputeCrc(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc); + + uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc); bool firstCrc = true; uint16_t tempCrc = 0; void WriteMagicNumber(); + TimerHandle_t notificationTimer; + + uint16_t notificatonConnectionHandle = 0; + size_t notificationSize = 0; + uint8_t notificationBuffer[10]; }; } } \ No newline at end of file diff --git a/src/DisplayApp/Screens/FirmwareUpdate.cpp b/src/DisplayApp/Screens/FirmwareUpdate.cpp index f3cf42f9..138211c4 100644 --- a/src/DisplayApp/Screens/FirmwareUpdate.cpp +++ b/src/DisplayApp/Screens/FirmwareUpdate.cpp @@ -26,6 +26,15 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime lv_label_set_text(percentLabel, ""); lv_obj_set_auto_realign(percentLabel, true); lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60); + + button = lv_btn_create(lv_scr_act(), NULL); + //lv_obj_set_event_cb(button, event_handler); + lv_obj_align(button, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_hidden(button, true); + + labelBtn = lv_label_create(button, NULL); + lv_label_set_text(labelBtn, "Back"); + lv_obj_set_hidden(labelBtn, true); } FirmwareUpdate::~FirmwareUpdate() { @@ -33,6 +42,29 @@ FirmwareUpdate::~FirmwareUpdate() { } bool FirmwareUpdate::Refresh() { + switch(bleController.State()) { + default: + case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle: + case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running: + if(state != States::Running) + state = States::Running; + return DisplayProgression(); + case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated: + if(state != States::Validated) { + UpdateValidated(); + state = States::Validated; + } + return running; + case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error: + if(state != States::Error) { + UpdateError(); + state = States::Error; + } + return running; + } +} + +bool FirmwareUpdate::DisplayProgression() const { float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f; float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f; int16_t pc = (current / total) * 100.0f; @@ -47,3 +79,16 @@ bool FirmwareUpdate::OnButtonPushed() { running = false; return true; } + +void FirmwareUpdate::UpdateValidated() { + lv_label_set_recolor(percentLabel, true); + lv_label_set_text(percentLabel, "#00ff00 Image Ok!#"); +} + +void FirmwareUpdate::UpdateError() { + lv_label_set_recolor(percentLabel, true); + lv_label_set_text(percentLabel, "#ff0000 Error!#"); + + lv_obj_set_hidden(labelBtn, false); + lv_obj_set_hidden(button, false); +} diff --git a/src/DisplayApp/Screens/FirmwareUpdate.h b/src/DisplayApp/Screens/FirmwareUpdate.h index a4cbec62..87e93959 100644 --- a/src/DisplayApp/Screens/FirmwareUpdate.h +++ b/src/DisplayApp/Screens/FirmwareUpdate.h @@ -26,13 +26,22 @@ namespace Pinetime { bool OnButtonPushed() override; private: + enum class States { Idle, Running, Validated, Error }; Pinetime::Controllers::Ble& bleController; - lv_obj_t * bar1; - lv_obj_t * percentLabel; - lv_obj_t * titleLabel; - char percentStr[10]; + lv_obj_t* bar1; + lv_obj_t* percentLabel; + lv_obj_t* titleLabel; + lv_obj_t* labelBtn; + lv_obj_t* button; + mutable char percentStr[10]; bool running = true; + States state; + bool DisplayProgression() const; + + void UpdateValidated(); + + void UpdateError(); }; } } diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 3a85ba76..7bba3c3e 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -118,6 +118,7 @@ void SystemTask::Work() { break; case Messages::BleFirmwareUpdateFinished: displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateFinished); + NVIC_SystemReset(); break; default: break; } -- cgit v1.2.3 From 07f74cee63d77882191c8ce53c598f91e6159ba8 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 1 Jun 2020 16:30:24 +0200 Subject: DFU : add timeout detection : abort dfu procedure after 10s without any data from the host. --- src/Components/Ble/DfuService.cpp | 46 +++++++++++++++++++++++++------ src/Components/Ble/DfuService.h | 7 +++-- src/DisplayApp/DisplayApp.cpp | 6 +--- src/DisplayApp/Screens/FirmwareUpdate.cpp | 12 -------- src/DisplayApp/Screens/FirmwareUpdate.h | 2 -- src/FreeRTOSConfig.h | 2 +- src/SystemTask/SystemTask.cpp | 3 +- 7 files changed, 45 insertions(+), 33 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 0d67d848..38a550f0 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -16,11 +16,16 @@ int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); } -void NotificationTimerCallback( TimerHandle_t xTimer ) { - auto dfuService = static_cast(pvTimerGetTimerID( xTimer )); +void NotificationTimerCallback(TimerHandle_t xTimer) { + auto dfuService = static_cast(pvTimerGetTimerID(xTimer)); dfuService->OnNotificationTimer(); } +void TimeoutTimerCallback(TimerHandle_t xTimer) { + auto dfuService = static_cast(pvTimerGetTimerID(xTimer)); + dfuService->OnTimeout(); +} + DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, Pinetime::Drivers::SpiNorFlash &spiNorFlash) : systemTask{systemTask}, @@ -66,6 +71,7 @@ DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Contr }, } { notificationTimer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback); + timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback); } void DfuService::Init() { @@ -74,6 +80,10 @@ void DfuService::Init() { } int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { + if(bleController.IsFirmwareUpdating()){ + xTimerStart(timeoutTimer, 0); + } + ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle); @@ -150,11 +160,6 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { nbPacketReceived++; auto offset = ((nbPacketReceived - 1) % nbPacketsToNotify) * 20; std::memcpy(tempBuffer + offset, om->om_data, om->om_len); - if (firstCrc) { - tempCrc = ComputeCrc(om->om_data, om->om_len, NULL); - firstCrc = false; - } else - tempCrc = ComputeCrc(om->om_data, om->om_len, &tempCrc); if (nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { #if 1 @@ -190,7 +195,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; - NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received! CRC = %u -- %d", tempCrc, connectionHandle); + NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); SendNotification(connectionHandle, data, 3); state = States::Validate; } @@ -266,7 +271,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { return 0; case Opcodes::ValidateFirmware: { if (state != States::Validate) { - NRF_LOG_INFO("[DFU] -> Validate firmware image requested, but we are not in Data state"); + NRF_LOG_INFO("[DFU] -> Validate firmware image requested, but we are not in Data state %d", state); return 0; } @@ -301,6 +306,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Activate image and reset!"); bleController.StopFirmwareUpdate(); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished); + Reset(); + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); return 0; default: return 0; @@ -375,3 +382,24 @@ void DfuService::OnNotificationTimer() { notificationSize = 0; } } + +void DfuService::OnTimeout() { + Reset(); +} + +void DfuService::Reset() { + state = States::Idle; + nbPacketsToNotify = 0; + nbPacketReceived = 0; + bytesReceived = 0; + softdeviceSize = 0; + bootloaderSize = 0; + applicationSize = 0; + expectedCrc = 0; + notificatonConnectionHandle = 0; + notificationSize = 0; + xTimerStop(notificationTimer, 0); + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); + bleController.StopFirmwareUpdate(); + systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished); +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 3de17f9f..73846c86 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -26,6 +26,9 @@ namespace Pinetime { int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); void OnNotificationTimer(); + void OnTimeout(); + + void Reset(); private: Pinetime::System::SystemTask &systemTask; @@ -125,11 +128,9 @@ namespace Pinetime { uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc); - bool firstCrc = true; - uint16_t tempCrc = 0; - void WriteMagicNumber(); TimerHandle_t notificationTimer; + TimerHandle_t timeoutTimer; uint16_t notificatonConnectionHandle = 0; size_t notificationSize = 0; diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index c42639c7..01c3aa96 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -163,12 +163,8 @@ void DisplayApp::Refresh() { lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); currentScreen.reset(nullptr); currentScreen.reset(new Screens::FirmwareUpdate(this, bleController)); + onClockApp = false; - break; - case Messages::BleFirmwareUpdateFinished: - lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); - currentScreen.reset(nullptr); - currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); break; } } diff --git a/src/DisplayApp/Screens/FirmwareUpdate.cpp b/src/DisplayApp/Screens/FirmwareUpdate.cpp index 138211c4..e831114d 100644 --- a/src/DisplayApp/Screens/FirmwareUpdate.cpp +++ b/src/DisplayApp/Screens/FirmwareUpdate.cpp @@ -26,15 +26,6 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime lv_label_set_text(percentLabel, ""); lv_obj_set_auto_realign(percentLabel, true); lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60); - - button = lv_btn_create(lv_scr_act(), NULL); - //lv_obj_set_event_cb(button, event_handler); - lv_obj_align(button, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - lv_obj_set_hidden(button, true); - - labelBtn = lv_label_create(button, NULL); - lv_label_set_text(labelBtn, "Back"); - lv_obj_set_hidden(labelBtn, true); } FirmwareUpdate::~FirmwareUpdate() { @@ -88,7 +79,4 @@ void FirmwareUpdate::UpdateValidated() { void FirmwareUpdate::UpdateError() { lv_label_set_recolor(percentLabel, true); lv_label_set_text(percentLabel, "#ff0000 Error!#"); - - lv_obj_set_hidden(labelBtn, false); - lv_obj_set_hidden(button, false); } diff --git a/src/DisplayApp/Screens/FirmwareUpdate.h b/src/DisplayApp/Screens/FirmwareUpdate.h index 87e93959..a571d667 100644 --- a/src/DisplayApp/Screens/FirmwareUpdate.h +++ b/src/DisplayApp/Screens/FirmwareUpdate.h @@ -31,8 +31,6 @@ namespace Pinetime { lv_obj_t* bar1; lv_obj_t* percentLabel; lv_obj_t* titleLabel; - lv_obj_t* labelBtn; - lv_obj_t* button; mutable char percentStr[10]; bool running = true; States state; diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 557e5edf..93289e1a 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -96,7 +96,7 @@ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY ( 0 ) #define configTIMER_QUEUE_LENGTH 32 -#define configTIMER_TASK_STACK_DEPTH ( 120 ) +#define configTIMER_TASK_STACK_DEPTH ( 240 ) /* Tickless Idle configuration. */ #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 7bba3c3e..eb36c7b8 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -118,7 +118,8 @@ void SystemTask::Work() { break; case Messages::BleFirmwareUpdateFinished: displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateFinished); - NVIC_SystemReset(); + if(bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) + NVIC_SystemReset(); break; default: break; } -- cgit v1.2.3 From f6aa41c214eef418b55cf0f063c5a296b1e57b63 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 1 Jun 2020 17:35:28 +0200 Subject: Encapsulate notification send (sync/async) into DfuService::NotificationManager; --- src/Components/Ble/DfuService.cpp | 110 +++++++++++++++++++++----------------- src/Components/Ble/DfuService.h | 34 ++++++------ 2 files changed, 78 insertions(+), 66 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index 38a550f0..a170fdfa 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -17,8 +17,8 @@ int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, } void NotificationTimerCallback(TimerHandle_t xTimer) { - auto dfuService = static_cast(pvTimerGetTimerID(xTimer)); - dfuService->OnNotificationTimer(); + auto notificationManager = static_cast(pvTimerGetTimerID(xTimer)); + notificationManager->OnNotificationTimer(); } void TimeoutTimerCallback(TimerHandle_t xTimer) { @@ -70,7 +70,6 @@ DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Contr 0 }, } { - notificationTimer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback); timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback); } @@ -132,7 +131,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { } uint8_t data[]{16, 1, 1}; - SendNotification(connectionHandle, data, 3); + notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3); state = States::Init; } return 0; @@ -162,30 +161,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { std::memcpy(tempBuffer + offset, om->om_data, om->om_len); if (nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { -#if 1 spiNorFlash.Write(writeOffset + ((nbPacketReceived - nbPacketsToNotify) * 20), tempBuffer, 200); -#endif } - bytesReceived += om->om_len; bleController.FirmwareUpdateCurrentBytes(bytesReceived); - //NRF_LOG_INFO("[DFU] -> Bytes received : %d in %d packets", bytesReceived, nbPacketReceived); - - if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) { uint8_t data[5]{static_cast(Opcodes::PacketReceiptNotification), (uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u), (uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)}; NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived); - SendNotification(connectionHandle, data, 5); + notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5); } if (bytesReceived == applicationSize) { if ((nbPacketReceived % nbPacketsToNotify) != 0) { auto remaningPacket = nbPacketReceived % nbPacketsToNotify; - uint32_t spiOffset = writeOffset + ((nbPacketReceived - remaningPacket) * 20); - spiNorFlash.Write(writeOffset + ((nbPacketReceived - remaningPacket) * 20), tempBuffer, remaningPacket * 20); } @@ -196,7 +187,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); - SendNotification(connectionHandle, data, 3); + notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3); state = States::Validate; } } @@ -247,12 +238,12 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete"); if (isInitComplete) { - notificationBuffer[0] = static_cast(Opcodes::Response); - notificationBuffer[1] = static_cast(Opcodes::InitDFUParameters); - notificationBuffer[2] = (isInitComplete ? uint8_t{1} : uint8_t{0}); - notificationSize = 3; - notificatonConnectionHandle = connectionHandle; - xTimerStart(notificationTimer, 0); + uint8_t data[3] { + static_cast(Opcodes::Response), + static_cast(Opcodes::InitDFUParameters), + (isInitComplete ? uint8_t{1} : uint8_t{0}) + }; + notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); return 0; } } @@ -279,21 +270,19 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { if(Validate()){ state = States::Validated; - - notificationBuffer[0] = static_cast(Opcodes::Response); - notificationBuffer[1] = static_cast(Opcodes::ValidateFirmware); - notificationBuffer[2] = static_cast(ErrorCodes::NoError); - notificationSize = 3; - notificatonConnectionHandle = connectionHandle; - xTimerStart(notificationTimer, 0); - + uint8_t data[3] { + static_cast(Opcodes::Response), + static_cast(Opcodes::ValidateFirmware), + static_cast(ErrorCodes::NoError) + }; + notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); } else { - notificationBuffer[0] = static_cast(Opcodes::Response); - notificationBuffer[1] = static_cast(Opcodes::ValidateFirmware); - notificationBuffer[2] = static_cast(ErrorCodes::CrcError); - notificationSize = 3; - notificatonConnectionHandle = connectionHandle; - xTimerStart(notificationTimer, 0); + uint8_t data[3] { + static_cast(Opcodes::Response), + static_cast(Opcodes::ValidateFirmware), + static_cast(ErrorCodes::CrcError) + }; + notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); } return 0; @@ -314,11 +303,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { } } -void DfuService::SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size) { - auto *om = ble_hs_mbuf_from_flat(data, size); - auto ret = ble_gattc_notify_custom(connectionHandle, controlPointCharacteristicHandle, om); - ASSERT(ret == 0); -} + uint16_t DfuService::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) { uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; @@ -376,13 +361,6 @@ void DfuService::WriteMagicNumber() { spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); } -void DfuService::OnNotificationTimer() { - if(notificationSize > 0) { - SendNotification(notificatonConnectionHandle, notificationBuffer, notificationSize); - notificationSize = 0; - } -} - void DfuService::OnTimeout() { Reset(); } @@ -396,10 +374,44 @@ void DfuService::Reset() { bootloaderSize = 0; applicationSize = 0; expectedCrc = 0; - notificatonConnectionHandle = 0; - notificationSize = 0; - xTimerStop(notificationTimer, 0); + notificationManager.Reset(); bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); bleController.StopFirmwareUpdate(); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished); } + +DfuService::NotificationManager::NotificationManager() { + timer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback); +} + +bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t s) { + if(size != 0 || s > 10) + return false; + + connectionHandle = connection; + characteristicHandle = charactHandle; + size = s; + std::memcpy(buffer, data, size); + xTimerStart(timer, 0); + return true; +} + +void DfuService::NotificationManager::OnNotificationTimer() { + if(size > 0) { + Send(connectionHandle, characteristicHandle, buffer, size); + size = 0; + } +} + +void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t *data, const size_t s) { + auto *om = ble_hs_mbuf_from_flat(data, s); + auto ret = ble_gattc_notify_custom(connection, charactHandle, om); + ASSERT(ret == 0); +} + +void DfuService::NotificationManager::Reset() { + connectionHandle = 0; + characteristicHandle = 0; + size = 0; + xTimerStop(timer, 0); +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index 73846c86..b0eccdf5 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -19,17 +19,28 @@ namespace Pinetime { public: DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, Pinetime::Drivers::SpiNorFlash &spiNorFlash); - void Init(); - bool Validate(); - int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); - void OnNotificationTimer(); 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(); + }; + private: Pinetime::System::SystemTask &systemTask; Pinetime::Controllers::Ble &bleController; @@ -117,24 +128,13 @@ namespace Pinetime { uint16_t expectedCrc = 0; int SendDfuRevision(os_mbuf *om) const; - - void SendNotification(uint16_t connectionHandle, const uint8_t *data, const size_t size); - int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); - int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om); - uint8_t tempBuffer[200]; - uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc); - void WriteMagicNumber(); - TimerHandle_t notificationTimer; TimerHandle_t timeoutTimer; - - uint16_t notificatonConnectionHandle = 0; - size_t notificationSize = 0; - uint8_t notificationBuffer[10]; + NotificationManager notificationManager; }; } } \ No newline at end of file -- cgit v1.2.3 From de822cc3a2f07033e881331ac8914b26023bb003 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 1 Jun 2020 18:32:46 +0200 Subject: Encapsulate DFU Image buffering and writing into spi flash in DfuImage. Add some const in SPI driver. --- src/CMakeLists.txt | 4 +- src/Components/Ble/DfuService.cpp | 181 +++++++++++++++++++++----------------- src/Components/Ble/DfuService.h | 37 ++++++-- src/drivers/Spi.cpp | 2 +- src/drivers/Spi.h | 2 +- src/drivers/SpiMaster.cpp | 2 +- src/drivers/SpiMaster.h | 2 +- src/drivers/SpiNorFlash.cpp | 4 +- src/drivers/SpiNorFlash.h | 2 +- 9 files changed, 137 insertions(+), 99 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c37a05a6..4799ea1c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -355,7 +355,6 @@ list(APPEND SOURCE_FILES Components/Ble/DfuService.cpp Components/Ble/CurrentTimeService.cpp Components/Ble/AlertNotificationService.cpp - Components/Ble/DfuImage.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -409,8 +408,7 @@ set(INCLUDE_FILES Components/Ble/CurrentTimeClient.h Components/Ble/AlertNotificationClient.h Components/Ble/DfuService.h - Components/Ble/DfuImage.h - drivers/Cst816s.h + drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h libs/date/includes/date/tz.h diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index a170fdfa..e4dcdf38 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -30,7 +30,7 @@ DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Contr Pinetime::Drivers::SpiNorFlash &spiNorFlash) : systemTask{systemTask}, bleController{bleController}, - spiNorFlash{spiNorFlash}, + dfuImage{spiNorFlash}, characteristicDefinition{ { .uuid = (ble_uuid_t *) &packetCharacteristicUuid, @@ -124,11 +124,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize); - for (int erased = 0; erased < maxImageSize; erased += 0x1000) { -#if 1 - spiNorFlash.SectorErase(writeOffset + erased); -#endif - } + dfuImage.Erase(); uint8_t data[]{16, 1, 1}; notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3); @@ -157,13 +153,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { case States::Data: { nbPacketReceived++; - auto offset = ((nbPacketReceived - 1) % nbPacketsToNotify) * 20; - std::memcpy(tempBuffer + offset, om->om_data, om->om_len); - - if (nbPacketReceived > 0 && (nbPacketReceived % nbPacketsToNotify) == 0) { - spiNorFlash.Write(writeOffset + ((nbPacketReceived - nbPacketsToNotify) * 20), tempBuffer, 200); - } - + dfuImage.Append(om->om_data, om->om_len); bytesReceived += om->om_len; bleController.FirmwareUpdateCurrentBytes(bytesReceived); @@ -174,15 +164,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived); notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5); } - if (bytesReceived == applicationSize) { - if ((nbPacketReceived % nbPacketsToNotify) != 0) { - auto remaningPacket = nbPacketReceived % nbPacketsToNotify; - spiNorFlash.Write(writeOffset + ((nbPacketReceived - remaningPacket) * 20), tempBuffer, remaningPacket * 20); - } - - if (applicationSize < maxImageSize) - WriteMagicNumber(); - + if (dfuImage.IsComplete()) { uint8_t data[3]{static_cast(Opcodes::Response), static_cast(Opcodes::ReceiveFirmwareImage), static_cast(ErrorCodes::NoError)}; @@ -257,6 +239,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start Init"); return 0; } + // TODO the chunk size is dependant of the implementation of the host application... + dfuImage.Init(20, applicationSize, expectedCrc); NRF_LOG_INFO("[DFU] -> Starting receive firmware"); state = States::Data; return 0; @@ -268,8 +252,11 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle); - if(Validate()){ + if(dfuImage.Validate()){ state = States::Validated; + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); + NRF_LOG_INFO("Image OK"); + uint8_t data[3] { static_cast(Opcodes::Response), static_cast(Opcodes::ValidateFirmware), @@ -277,6 +264,9 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { }; notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); } else { + bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); + NRF_LOG_INFO("Image Error : bad CRC"); + uint8_t data[3] { static_cast(Opcodes::Response), static_cast(Opcodes::ValidateFirmware), @@ -303,64 +293,6 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { } } - - -uint16_t DfuService::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) { - uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; - - for (uint32_t i = 0; i < size; i++) { - crc = (uint8_t) (crc >> 8) | (crc << 8); - crc ^= p_data[i]; - crc ^= (uint8_t) (crc & 0xFF) >> 4; - crc ^= (crc << 8) << 4; - crc ^= ((crc & 0xFF) << 4) << 1; - } - - return crc; -} - -bool DfuService::Validate() { - uint32_t chunkSize = 200; - int currentOffset = 0; - uint16_t crc = 0; - - bool first = true; - while (currentOffset < applicationSize) { - uint32_t readSize = (applicationSize - currentOffset) > chunkSize ? chunkSize : (applicationSize - currentOffset); - - spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, readSize); - if (first) { - crc = ComputeCrc(tempBuffer, readSize, NULL); - first = false; - } else - crc = ComputeCrc(tempBuffer, readSize, &crc); - currentOffset += readSize; - } - - NRF_LOG_INFO("Expected CRC : %u - Processed CRC : %u", expectedCrc, crc); - bool crcOk = (crc == expectedCrc); - if (crcOk) { - bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); - NRF_LOG_INFO("Image OK"); - } else { - bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); - NRF_LOG_INFO("Image Error : bad CRC"); - } - return crcOk; -} - -void DfuService::WriteMagicNumber() { - uint32_t magic[4] = { - 0xf395c277, - 0x7fefd260, - 0x0f505235, - 0x8079b62c, - }; - - uint32_t offset = writeOffset + (maxImageSize - (4 * sizeof(uint32_t))); - spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); -} - void DfuService::OnTimeout() { Reset(); } @@ -415,3 +347,90 @@ void DfuService::NotificationManager::Reset() { size = 0; xTimerStop(timer, 0); } + +void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) { + if(chunkSize != 20) return; + this->chunkSize = chunkSize; + this->totalSize = totalSize; + this->expectedCrc = expectedCrc; + this->ready = true; +} + +void DfuService::DfuImage::Append(uint8_t *data, size_t size) { + if(!ready) return; + ASSERT(size <= 20); + + std::memcpy(tempBuffer + bufferWriteIndex, data, size); + bufferWriteIndex += size; + + if(bufferWriteIndex == bufferSize) { + spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex); + totalWriteIndex += bufferWriteIndex; + bufferWriteIndex = 0; + } + + if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) { + spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex); + totalWriteIndex += bufferWriteIndex; + if (totalSize < maxSize); + WriteMagicNumber(); + } +} + +void DfuService::DfuImage::WriteMagicNumber() { + static constexpr uint32_t magic[4] = { + 0xf395c277, + 0x7fefd260, + 0x0f505235, + 0x8079b62c, + }; + + uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t))); + spiNorFlash.Write(offset, reinterpret_cast(magic), 4 * sizeof(uint32_t)); +} + +void DfuService::DfuImage::Erase() { + for (int erased = 0; erased < maxSize; erased += 0x1000) { + spiNorFlash.SectorErase(writeOffset + erased); + } +} + +bool DfuService::DfuImage::Validate() { + uint32_t chunkSize = 200; + int currentOffset = 0; + uint16_t crc = 0; + + bool first = true; + while (currentOffset < totalSize) { + uint32_t readSize = (totalSize - currentOffset) > chunkSize ? chunkSize : (totalSize - currentOffset); + + spiNorFlash.Read(writeOffset + currentOffset, tempBuffer, readSize); + if (first) { + crc = ComputeCrc(tempBuffer, readSize, NULL); + first = false; + } else + crc = ComputeCrc(tempBuffer, readSize, &crc); + currentOffset += readSize; + } + + return (crc == expectedCrc); +} + +uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) { + uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; + + for (uint32_t i = 0; i < size; i++) { + crc = (uint8_t) (crc >> 8) | (crc << 8); + crc ^= p_data[i]; + crc ^= (uint8_t) (crc & 0xFF) >> 4; + crc ^= (crc << 8) << 4; + crc ^= ((crc & 0xFF) << 4) << 1; + } + + return crc; +} + +bool DfuService::DfuImage::IsComplete() { + if(!ready) return false; + return totalWriteIndex == totalSize; +} diff --git a/src/Components/Ble/DfuService.h b/src/Components/Ble/DfuService.h index b0eccdf5..d7ba460c 100644 --- a/src/Components/Ble/DfuService.h +++ b/src/Components/Ble/DfuService.h @@ -20,7 +20,6 @@ namespace Pinetime { DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, Pinetime::Drivers::SpiNorFlash &spiNorFlash); void Init(); - bool Validate(); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); void OnTimeout(); void Reset(); @@ -40,11 +39,38 @@ namespace Pinetime { 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; - Pinetime::Drivers::SpiNorFlash &spiNorFlash; + DfuImage dfuImage; + NotificationManager notificationManager; static constexpr uint16_t dfuServiceId{0x1530}; static constexpr uint16_t packetCharacteristicId{0x1532}; @@ -119,22 +145,17 @@ namespace Pinetime { uint8_t nbPacketsToNotify = 0; uint32_t nbPacketReceived = 0; uint32_t bytesReceived = 0; - uint32_t writeOffset = 0x40000; uint32_t softdeviceSize = 0; uint32_t bootloaderSize = 0; uint32_t applicationSize = 0; - static constexpr uint32_t maxImageSize = 475136; 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); - uint8_t tempBuffer[200]; - uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc); - void WriteMagicNumber(); + TimerHandle_t timeoutTimer; - NotificationManager notificationManager; }; } } \ No newline at end of file diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index ec3a5e94..bf08178d 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -27,7 +27,7 @@ bool Spi::Init() { return true; } -bool Spi::WriteCmdAndBuffer(uint8_t *cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { +bool Spi::WriteCmdAndBuffer(const uint8_t *cmd, size_t cmdSize, const uint8_t *data, size_t dataSize) { return spiMaster.WriteCmdAndBuffer(pinCsn, cmd, cmdSize, data, dataSize); } diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index bee39af2..82ba8a65 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -22,7 +22,7 @@ namespace Pinetime { bool Init(); bool Write(const uint8_t* data, size_t size); bool Read(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); - bool WriteCmdAndBuffer(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); + bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t *data, size_t dataSize); void Sleep(); void Wakeup(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index ff241184..8087d386 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -239,7 +239,7 @@ void SpiMaster::Wakeup() { Init(); } -bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, uint8_t *cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { +bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t *cmd, size_t cmdSize, const uint8_t *data, size_t dataSize) { xSemaphoreTake(mutex, portMAX_DELAY); taskToNotify = nullptr; diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 88b37a35..cd3193e4 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -37,7 +37,7 @@ namespace Pinetime { bool Write(uint8_t pinCsn, const uint8_t* data, size_t size); bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); - bool WriteCmdAndBuffer(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize); + bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t *data, size_t dataSize); void OnStartedEvent(); void OnEndEvent(); diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp index 8fbb53a1..7e4da1ca 100644 --- a/src/drivers/SpiNorFlash.cpp +++ b/src/drivers/SpiNorFlash.cpp @@ -96,12 +96,12 @@ bool SpiNorFlash::EraseFailed() { return (ReadSecurityRegister() & 0x40u) == 0x40u; } -void SpiNorFlash::Write(uint32_t address, uint8_t *buffer, size_t size) { +void SpiNorFlash::Write(uint32_t address, const uint8_t *buffer, size_t size) { static constexpr uint8_t cmdSize = 4; size_t len = size; uint32_t addr = address; - uint8_t* b = buffer; + const uint8_t* b = buffer; while(len > 0) { uint32_t pageLimit = (addr & ~(pageSize - 1u)) + pageSize; uint32_t toWrite = pageLimit - addr > len ? len : pageLimit - addr; diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h index b5f19202..98267c09 100644 --- a/src/drivers/SpiNorFlash.h +++ b/src/drivers/SpiNorFlash.h @@ -24,7 +24,7 @@ namespace Pinetime { bool WriteEnabled(); uint8_t ReadConfigurationRegister(); void Read(uint32_t address, uint8_t* buffer, size_t size); - void Write(uint32_t address, uint8_t *buffer, size_t size); + void Write(uint32_t address, const uint8_t *buffer, size_t size); void WriteEnable(); void SectorErase(uint32_t sectorAddress); uint8_t ReadSecurityRegister(); -- cgit v1.2.3 From e7723598a65c6c041e3b4dff4d0bb144d1c697a0 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 1 Jun 2020 20:40:11 +0200 Subject: Automatically go to sleep after 5 sec of inactivity. Advertise for 3 minutes at startup and on wake-up. Disable automatic continuous StartAdvertising. --- src/Components/Ble/NimbleController.cpp | 7 +++-- src/SystemTask/SystemTask.cpp | 53 ++++++++++++++++++++++++++++----- src/SystemTask/SystemTask.h | 9 +++++- 3 files changed, 58 insertions(+), 11 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 7a7753b1..4c8035b7 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -33,8 +33,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, spiNorFlash{spiNorFlash}, dfuService{systemTask, bleController, spiNorFlash}, currentTimeClient{dateTimeController}, - alertNotificationClient{systemTask, notificationManager}, anService{systemTask, notificationManager}, + alertNotificationClient{systemTask, notificationManager}, currentTimeService{dateTimeController} { } @@ -97,6 +97,8 @@ void NimbleController::Init() { } void NimbleController::StartAdvertising() { + if(ble_gap_adv_active()) return; + ble_svc_gap_device_name_set("Pinetime-JF"); /* set adv parameters */ @@ -136,7 +138,7 @@ void NimbleController::StartAdvertising() { res = ble_gap_adv_rsp_set_fields(&rsp_fields); // ASSERT(res == 0); - res = ble_gap_adv_start(addrType, NULL, 10000, + res = ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this); // ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu. // For now, the advertising is restarted as soon as it ends. There may be a race condition @@ -160,7 +162,6 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) { case BLE_GAP_EVENT_ADV_COMPLETE: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE"); NRF_LOG_INFO("advertise complete; reason=%dn status=%d", event->adv_complete.reason, event->connect.status); - StartAdvertising(); break; case BLE_GAP_EVENT_CONNECT: { NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT"); diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index eb36c7b8..b0f58d17 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -15,6 +15,12 @@ using namespace Pinetime::System; +void IdleTimerCallback(TimerHandle_t xTimer) { + auto sysTask = static_cast(pvTimerGetTimerID(xTimer)); + sysTask->OnIdle(); +} + + SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, Pinetime::Drivers::SpiNorFlash& spiNorFlash, Drivers::Cst816S &touchPanel, Components::LittleVgl &lvgl, @@ -92,35 +98,55 @@ void SystemTask::Work() { nrfx_gpiote_in_init(pinTouchIrq, &pinConfig, nrfx_gpiote_evt_handler); + idleTimer = xTimerCreate ("idleTimer", idleTime, pdFALSE, this, IdleTimerCallback); + xTimerStart(idleTimer, 0); while(true) { uint8_t msg; if (xQueueReceive(systemTaksMsgQueue, &msg, isSleeping?2500 : 1000)) { Messages message = static_cast(msg); switch(message) { - case Messages::GoToRunning: isSleeping = false; break; + case Messages::GoToRunning: + isSleeping = false; + xTimerStart(idleTimer, 0); + nimbleController.StartAdvertising(); + break; case Messages::GoToSleep: NRF_LOG_INFO("[SystemTask] Going to sleep"); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); - isSleeping = true; break; + isSleeping = true; + break; case Messages::OnNewTime: + xTimerReset(idleTimer, 0); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateDateTime); break; case Messages::OnNewNotification: + xTimerReset(idleTimer, 0); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewNotification); break; case Messages::BleConnected: + xTimerReset(idleTimer, 0); isBleDiscoveryTimerRunning = true; bleDiscoveryTimer = 5; break; case Messages::BleFirmwareUpdateStarted: + doNotGoToSleep = true; + if(isSleeping) GoToRunning(); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateStarted); break; case Messages::BleFirmwareUpdateFinished: + doNotGoToSleep = false; + xTimerStart(idleTimer, 0); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateFinished); if(bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) NVIC_SystemReset(); break; + case Messages::OnTouchEvent: + xTimerReset(idleTimer, 0); + break; + case Messages::OnButtonEvent: + xTimerReset(idleTimer, 0); + break; default: break; } } @@ -146,22 +172,29 @@ void SystemTask::Work() { } void SystemTask::OnButtonPushed() { - if(!isSleeping) { NRF_LOG_INFO("[SystemTask] Button pushed"); + PushMessage(Messages::OnButtonEvent); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::ButtonPushed); } else { NRF_LOG_INFO("[SystemTask] Button pushed, waking up"); - displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToRunning); - isSleeping = false; - displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateBatteryLevel); + GoToRunning(); } } +void SystemTask::GoToRunning() { + PushMessage(Messages::GoToRunning); + displayApp->PushMessage(Applications::DisplayApp::Messages::GoToRunning); + displayApp->PushMessage(Applications::DisplayApp::Messages::UpdateBatteryLevel); +} + void SystemTask::OnTouchEvent() { NRF_LOG_INFO("[SystemTask] Touch event"); - displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::TouchEvent); + if(!isSleeping) { + PushMessage(Messages::OnTouchEvent); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::TouchEvent); + } } void SystemTask::PushMessage(SystemTask::Messages msg) { @@ -173,3 +206,9 @@ void SystemTask::PushMessage(SystemTask::Messages msg) { // TODO : should I do something here? } } + +void SystemTask::OnIdle() { + if(doNotGoToSleep) return; + NRF_LOG_INFO("Idle timeout -> Going to sleep") + PushMessage(Messages::GoToSleep); +} diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index 53e69fa7..b6ecf7c9 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -16,7 +16,7 @@ namespace Pinetime { class SystemTask { public: enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, BleConnected, - BleFirmwareUpdateStarted, BleFirmwareUpdateFinished + BleFirmwareUpdateStarted, BleFirmwareUpdateFinished, OnTouchEvent, OnButtonEvent }; SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, @@ -32,6 +32,9 @@ namespace Pinetime { void OnButtonPushed(); void OnTouchEvent(); + + void OnIdle(); + private: TaskHandle_t taskHandle; @@ -64,7 +67,11 @@ namespace Pinetime { void Work(); bool isBleDiscoveryTimerRunning = false; uint8_t bleDiscoveryTimer = 0; + static constexpr uint32_t idleTime = 5000; + TimerHandle_t idleTimer; + bool doNotGoToSleep = false; + void GoToRunning(); }; } } \ No newline at end of file -- cgit v1.2.3 From dbdb26ae1fa45cec88f1b9ea0353b3d0a3c39f56 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 14:10:17 +0200 Subject: DfuService : fix Magic number : incorrect values were written in memory. --- src/Components/Ble/DfuService.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Components/Ble') diff --git a/src/Components/Ble/DfuService.cpp b/src/Components/Ble/DfuService.cpp index e4dcdf38..ff899e6f 100644 --- a/src/Components/Ble/DfuService.cpp +++ b/src/Components/Ble/DfuService.cpp @@ -372,13 +372,13 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) { if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) { spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex); totalWriteIndex += bufferWriteIndex; - if (totalSize < maxSize); + if (totalSize < maxSize) WriteMagicNumber(); } } void DfuService::DfuImage::WriteMagicNumber() { - static constexpr uint32_t magic[4] = { + uint32_t magic[4] = { // TODO When this variable is a static constexpr, the values written to the memory are not correct. Why? 0xf395c277, 0x7fefd260, 0x0f505235, -- cgit v1.2.3