From 399734502dd7cab10f5cce218a1fc71b933a6a33 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 15 Nov 2016 00:09:29 +0100 Subject: [PATCH] Harmonize OTA code, reboot when flash is idle --- core/MyOTAFirmwareUpdate.cpp | 140 +++++++++++++++++++---------------- core/MyOTAFirmwareUpdate.h | 39 +++++----- core/MySensorsCore.cpp | 2 +- 3 files changed, 97 insertions(+), 84 deletions(-) diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index af0338e..02749c1 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -22,94 +22,98 @@ // global variables extern MyMessage _msg; extern MyMessage _msgTmp; -extern NodeConfig _nc; // local variables SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); -NodeFirmwareConfig _fc; -bool _fwUpdateOngoing; -unsigned long _fwLastRequestTime; -uint16_t _fwBlock; -uint8_t _fwRetry; +nodeFirmwareConfig_t _nodeFirmwareConfig; +bool _firmwareUpdateOngoing; +uint32_t _firmwareLastRequest; +uint16_t _firmwareBlock; +uint8_t _firmwareRetry; -void readFirmwareSettings() { - hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); +void readFirmwareSettings(void) +{ + hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); } -void firmwareOTAUpdateRequest() { - unsigned long enter = hwMillis(); - if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { - if (!_fwRetry) { +void firmwareOTAUpdateRequest(void) +{ + const uint32_t enterMS = hwMillis(); + if (_firmwareUpdateOngoing && (enterMS - _firmwareLastRequest > MY_OTA_RETRY_DELAY)) { + if (!_firmwareRetry) { setIndication(INDICATION_ERR_FW_TIMEOUT); OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed // Give up. We have requested MY_OTA_RETRY times without any packet in return. - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; return; } - _fwRetry--; - _fwLastRequestTime = enter; + _firmwareRetry--; + _firmwareLastRequest = enterMS; // Time to (re-)request firmware block from controller - RequestFWBlock firmwareRequest; - firmwareRequest.type = _fc.type; - firmwareRequest.version = _fc.version; - firmwareRequest.block = (_fwBlock - 1); - OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1); // request FW update block - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock))); + requestFirmwareBlock_t firmwareRequest; + firmwareRequest.type = _nodeFirmwareConfig.type; + firmwareRequest.version = _nodeFirmwareConfig.version; + firmwareRequest.block = (_firmwareBlock - 1); + OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type, _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t))); } } -bool firmwareOTAUpdateProcess() { +bool firmwareOTAUpdateProcess(void) +{ if (_msg.type == ST_FIRMWARE_CONFIG_RESPONSE) { - NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; - // compare with current node configuration, if they differ, start fw fetch process - if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + nodeFirmwareConfig_t *firmwareConfigResponse = (nodeFirmwareConfig_t *)_msg.data; + // compare with current node configuration, if they differ, start FW fetch process + if (memcmp(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t))) { setIndication(INDICATION_FW_UPDATE_START); OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated // copy new FW config - memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); + (void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t)); // Init flash if (!_flash.initialize()) { setIndication(INDICATION_ERR_FW_FLASH_INIT); OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; } else { // erase lower 32K -> max flash size for ATMEGA328 _flash.blockErase32K(0); // wait until flash erased while ( _flash.busy() ) {} - _fwBlock = _fc.blocks; - _fwUpdateOngoing = true; + _firmwareBlock = _nodeFirmwareConfig.blocks; + _firmwareUpdateOngoing = true; // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; + _firmwareRetry = MY_OTA_RETRY + 1; + _firmwareLastRequest = 0; } return true; } OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available } else if (_msg.type == ST_FIRMWARE_RESPONSE) { - if (_fwUpdateOngoing) { + if (_firmwareUpdateOngoing) { // Save block to flash setIndication(INDICATION_FW_UPDATE_RX); - OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _fwBlock); // received FW block + OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _firmwareBlock); // received FW block // extract FW block - ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; + replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data; // write to flash - _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written - while ( _flash.busy() ) {} - _fwBlock--; - if (!_fwBlock) { + while (_flash.busy()) {} + _firmwareBlock--; + if (!_firmwareBlock) { // We're finished! Do a checksum and reboot. OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; if (transportIsValidFirmware()) { OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok - // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; - uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(uint8_t)(fwsize >> 8),(uint8_t)(fwsize & 0xff),':'}; - _flash.writeBytes(0, OTAbuffer, 10); // Write the new firmware config to eeprom - hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks; + const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'}; + _flash.writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET); + // wait until flash ready + while (_flash.busy()) {} hwReboot(); } else { setIndication(INDICATION_ERR_FW_CHECKSUM); @@ -117,8 +121,8 @@ bool firmwareOTAUpdateProcess() { } } // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; + _firmwareRetry = MY_OTA_RETRY + 1; + _firmwareLastRequest = 0; } else { OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n")); } @@ -127,32 +131,38 @@ bool firmwareOTAUpdateProcess() { return false; } -void presentBootloaderInformation(){ - RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msgTmp.data; - mSetLength(_msgTmp, sizeof(RequestFirmwareConfig)); +void presentBootloaderInformation(void) +{ + requestFirmwareConfig_t *requestFirmwareConfig = (requestFirmwareConfig_t *)_msgTmp.data; + mSetLength(_msgTmp, sizeof(requestFirmwareConfig_t)); mSetCommand(_msgTmp, C_STREAM); - mSetPayloadType(_msgTmp,P_CUSTOM); + mSetPayloadType(_msgTmp, P_CUSTOM); // copy node settings to reqFWConfig - memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig)); + (void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t)); // add bootloader information - reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; - _fwUpdateOngoing = false; - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; + _firmwareUpdateOngoing = false; + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); +} +bool isFirmwareUpdateOngoing(void) +{ + return _firmwareUpdateOngoing; } // do a crc16 on the whole received firmware -bool transportIsValidFirmware() { +bool transportIsValidFirmware(void) +{ // init crc uint16_t crc = ~0; - for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { + for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) { crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); - for (int8_t j = 0; j < 8; ++j) { - if (crc & 1) { - crc = (crc >> 1) ^ 0xA001; - } - else { - crc = (crc >> 1); - } - } + for (int8_t j = 0; j < 8; ++j) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xA001; + } + else { + crc = (crc >> 1); + } + } } - return crc == _fc.crc; + return crc == _nodeFirmwareConfig.crc; } diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 1f76540..24846d8 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -56,18 +56,21 @@ #include "MySensorsCore.h" -#define FIRMWARE_BLOCK_SIZE (16) //!< Size of each firmware block -#define FIRMWARE_MAX_REQUESTS (5) //!< Number of times a firmware block should be requested before giving up -#define MY_OTA_RETRY (5) //!< Number of times to request a fw block before giving up -#define MY_OTA_RETRY_DELAY (500) //!< Number of milliseconds before re-requesting a FW block -#define FIRMWARE_START_OFFSET (10) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block +#define FIRMWARE_MAX_REQUESTS (5u) //!< Number of times a firmware block should be requested before giving up +#define MY_OTA_RETRY (5u) //!< Number of times to request a fw block before giving up +#define MY_OTA_RETRY_DELAY (500u) //!< Number of milliseconds before re-requesting a FW block +#define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) -#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3) //!< Bootloader version major -#define MY_OTA_BOOTLOADER_MINOR_VERSION (0) //!< Bootloader version minor +#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major +#define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor #define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version -#define OTA_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug - +#if defined(MY_DEBUG) + #define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +#else + #define OTA_DEBUG(x,...) //!< debug NULL +#endif /** * @brief FW config structure, stored in eeprom */ @@ -76,7 +79,7 @@ typedef struct { uint16_t version; //!< Version of config uint16_t blocks; //!< Number of blocks uint16_t crc; //!< CRC of block data -} __attribute__((packed)) NodeFirmwareConfig; +} __attribute__((packed)) nodeFirmwareConfig_t; /** * @brief FW config request structure @@ -87,7 +90,7 @@ typedef struct { uint16_t blocks; //!< Number of blocks uint16_t crc; //!< CRC of block data uint16_t BLVersion; //!< Bootloader version -} __attribute__((packed)) RequestFirmwareConfig; +} __attribute__((packed)) requestFirmwareConfig_t; /** * @brief FW block request structure @@ -96,7 +99,7 @@ typedef struct { uint16_t type; //!< Type of config uint16_t version; //!< Version of config uint16_t block; //!< Block index -} __attribute__((packed)) RequestFWBlock; +} __attribute__((packed)) requestFirmwareBlock_t; /** * @brief FW block reply structure @@ -106,7 +109,7 @@ typedef struct { uint16_t version; //!< Version of config uint16_t block; //!< Block index uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data -} __attribute__((packed)) ReplyFWBlock; +} __attribute__((packed)) replyFirmwareBlock_t; /** @@ -114,27 +117,27 @@ typedef struct { * * Current firmware settings (type, version, crc, blocks) are read into _fc */ -void readFirmwareSettings(); +void readFirmwareSettings(void); /** * @brief Handle OTA FW update requests */ - void firmwareOTAUpdateRequest(); +void firmwareOTAUpdateRequest(void); /** * @brief Handle OTA FW update responses * * This function handles incoming OTA FW packets and stores them to external flash (Sensebender) */ -bool firmwareOTAUpdateProcess(); +bool firmwareOTAUpdateProcess(void); /** * @brief Validate uploaded FW CRC * * This function verifies if uploaded FW CRC is valid */ -bool transportIsValidFirmware(); +bool transportIsValidFirmware(void); /** * @brief Present bootloader/FW information upon startup */ -void presentBootloaderInformation(); +void presentBootloaderInformation(void); #endif diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 80c32e3..fe9e7a7 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -468,7 +468,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in debug(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); // OTA FW feature: do not sleep if FW update ongoing #if defined(MY_OTA_FIRMWARE_FEATURE) - if (_fwUpdateOngoing) { + if (isFirmwareUpdateOngoing()) { debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing wait(sleepingMS); return MY_SLEEP_NOT_POSSIBLE;