Skip to content

Commit fe42dbd

Browse files
d00616mfalkvidd
authored andcommitted
Nvm fota (#1018)
* New Firmware OTA for NVM/mcuboot (nRF5) - Support for mcuboot (nRF5) - Support for run length encoded data - Support for smaller FIRMWARE_BLOCK_SIZE, if required * Update NVM * New MY_LOCK_MCU for NRF5 * Test with Sensebender GW + Sensebender Micro was successful
1 parent 599c0ba commit fe42dbd

File tree

9 files changed

+290
-104
lines changed

9 files changed

+290
-104
lines changed

MyConfig.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,23 @@
16541654
#define MY_SIGNING_SOFT_RANDOMSEED_PIN (7)
16551655
#endif
16561656

1657+
/**
1658+
* @def MY_LOCK_DEVICE
1659+
* @brief Enable read back protection
1660+
*
1661+
* Enable read back protection feature. Currently only supported by NRF51+NRF52.
1662+
* Use this flag to protect signing and encryption keys stored in the MCU.
1663+
*
1664+
* Set this flag, when you use softsigning in MySensors. Don't set this
1665+
* in SecurityPersonalizer.
1666+
*
1667+
* @warning YOU CAN BRICK YOUR DEVICE!!!
1668+
* Don't set this flag without having an boot loader, OTA firmware update and
1669+
* an Gateway connection. To reset an device, you can try >>
1670+
* openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c "program dap apreg 1 0x04 0x01"
1671+
*/
1672+
//#define MY_LOCK_DEVICE
1673+
16571674
/**
16581675
* @def MY_SIGNING_FEATURE
16591676
* @ingroup internals
@@ -2023,6 +2040,7 @@
20232040
#define MY_INDICATION_HANDLER
20242041
#define MY_DISABLE_REMOTE_RESET
20252042
#define MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
2043+
#define MY_LOCK_DEVICE
20262044
// core
20272045
#define MY_CORE_ONLY
20282046
// GW

MySensors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,13 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
126126

127127
// FLASH
128128
#if defined(MY_OTA_FIRMWARE_FEATURE)
129+
#ifndef MCUBOOT_PRESENT
129130
#if defined(MY_OTA_USE_I2C_EEPROM)
130131
#include "drivers/I2CEeprom/I2CEeprom.cpp"
131132
#else
132133
#include "drivers/SPIFlash/SPIFlash.cpp"
133134
#endif
135+
#endif
134136
#include "core/MyOTAFirmwareUpdate.cpp"
135137
#endif
136138

core/MyMessage.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ typedef enum {
208208
ST_FIRMWARE_REQUEST = 2, //!< Request FW block
209209
ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
210210
ST_SOUND = 4, //!< Sound
211-
ST_IMAGE = 5 //!< Image
211+
ST_IMAGE = 5, //!< Image
212+
ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
213+
ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data
212214
} mysensor_stream;
213215

214216
/// @brief Type of payload

core/MyOTAFirmwareUpdate.cpp

Lines changed: 142 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,30 @@ extern MyMessage _msgTmp;
2626
// local variables
2727
#ifdef MY_OTA_USE_I2C_EEPROM
2828
I2CEeprom _flash(MY_OTA_I2C_ADDR);
29-
#else
29+
#elif !defined(MCUBOOT_PRESENT)
3030
SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
3131
#endif
3232

33+
// Map flash functions
34+
#ifndef MCUBOOT_PRESENT
35+
#define _flash_initialize() _flash.initialize()
36+
#define _flash_readByte(addr) _flash.readByte(addr)
37+
#define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size)
38+
#define _flash_blockErase32K(num) _flash.blockErase32K(num)
39+
#define _flash_busy() _flash.busy()
40+
#else
41+
#define _flash_initialize() true
42+
#define _flash_readByte(addr) (*((uint8_t *)(addr)))
43+
#define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0)
44+
#define _flash_busy() false
45+
#endif
46+
3347
LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig;
3448
LOCAL bool _firmwareUpdateOngoing = false;
3549
LOCAL uint32_t _firmwareLastRequest;
3650
LOCAL uint16_t _firmwareBlock;
3751
LOCAL uint8_t _firmwareRetry;
52+
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data);
3853

3954
LOCAL void readFirmwareSettings(void)
4055
{
@@ -83,15 +98,15 @@ LOCAL bool firmwareOTAUpdateProcess(void)
8398
// copy new FW config
8499
(void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
85100
// Init flash
86-
if (!_flash.initialize()) {
101+
if (!_flash_initialize()) {
87102
setIndication(INDICATION_ERR_FW_FLASH_INIT);
88103
OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
89104
_firmwareUpdateOngoing = false;
90105
} else {
91106
// erase lower 32K -> max flash size for ATMEGA328
92-
_flash.blockErase32K(0);
107+
_flash_blockErase32K(0);
93108
// wait until flash erased
94-
while ( _flash.busy() ) {}
109+
while ( _flash_busy() ) {}
95110
_firmwareBlock = _nodeFirmwareConfig.blocks;
96111
_firmwareUpdateOngoing = true;
97112
// reset flags
@@ -102,68 +117,46 @@ LOCAL bool firmwareOTAUpdateProcess(void)
102117
}
103118
OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available
104119
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
105-
if (_firmwareUpdateOngoing) {
106-
// extract FW block
107-
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
108-
109-
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), firmwareResponse->block); // received FW block
110-
if (firmwareResponse->block != _firmwareBlock - 1) {
111-
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
112-
// wrong firmware block received
113-
setIndication(INDICATION_FW_UPDATE_RX_ERR);
114-
// no further processing required
115-
return true;
116-
}
117-
setIndication(INDICATION_FW_UPDATE_RX);
118-
// Save block to flash
119-
_flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
120-
firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
121-
// wait until flash written
122-
while (_flash.busy()) {}
123-
#ifdef OTA_EXTRA_FLASH_DEBUG
124-
{
125-
char prbuf[8];
126-
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
127-
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
128-
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
129-
MY_SERIALDEVICE.print(prbuf);
130-
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
131-
uint8_t data = _flash.readByte(addr + i);
132-
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
133-
MY_SERIALDEVICE.print(prbuf);
134-
}
135-
OTA_DEBUG(PSTR("\n"));
136-
}
120+
// extract FW block
121+
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
122+
// Proceed firmware data
123+
return _firmwareResponse(firmwareResponse->block, firmwareResponse->data);
124+
#ifdef FIRMWARE_PROTOCOL_31
125+
} else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) {
126+
// RLE encoded block
127+
// extract FW block
128+
replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data;
129+
uint8_t data[FIRMWARE_BLOCK_SIZE];
130+
for (uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
131+
data[i]=firmwareResponse->data;
132+
}
133+
while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) {
134+
_firmwareResponse(firmwareResponse->block, data);
135+
firmwareResponse->number_of_blocks--;
136+
firmwareResponse->block--;
137+
}
138+
return true;
137139
#endif
138-
_firmwareBlock--;
139-
if (!_firmwareBlock) {
140-
// We're done! Do a checksum and reboot.
141-
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
142-
_firmwareUpdateOngoing = false;
143-
if (transportIsValidFirmware()) {
144-
OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
145-
// Write the new firmware config to eeprom
146-
hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
147-
sizeof(nodeFirmwareConfig_t));
148-
// All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
149-
const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks;
150-
const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'};
151-
_flash.writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
152-
// wait until flash ready
153-
while (_flash.busy()) {}
154-
hwReboot();
155-
} else {
156-
setIndication(INDICATION_ERR_FW_CHECKSUM);
157-
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
140+
} else {
141+
#ifdef MCUBOOT_PRESENT
142+
if (_msg.type == ST_FIRMWARE_CONFIRM) {
143+
if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) {
144+
if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) {
145+
// Calculate data word to write
146+
uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise
147+
uint32_t img_ok_data = *img_ok_base_addr;
148+
// Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01)
149+
uint8_t * img_ok_array = (uint8_t*)(&img_ok_data);
150+
img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE;
151+
// Write word back
152+
Flash.write(img_ok_base_addr, img_ok_data);
158153
}
154+
OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n"));
155+
} else {
156+
OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n"));
159157
}
160-
// reset flags
161-
_firmwareRetry = MY_OTA_RETRY + 1;
162-
_firmwareLastRequest = 0;
163-
} else {
164-
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
165158
}
166-
return true;
159+
#endif
167160
}
168161
return false;
169162
}
@@ -178,6 +171,18 @@ LOCAL void presentBootloaderInformation(void)
178171
(void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t));
179172
// add bootloader information
180173
requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
174+
#ifdef FIRMWARE_PROTOCOL_31
175+
requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE;
176+
#ifndef MCUBOOT_PRESENT
177+
requestFirmwareConfig->img_commited = 0x2;
178+
requestFirmwareConfig->img_revision = 0x00;
179+
requestFirmwareConfig->img_build_num = 0x00;
180+
#else
181+
requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR));
182+
requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR));
183+
requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR));
184+
#endif
185+
#endif
181186
_firmwareUpdateOngoing = false;
182187
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
183188
ST_FIRMWARE_CONFIG_REQUEST, false));
@@ -192,8 +197,8 @@ LOCAL bool transportIsValidFirmware(void)
192197
{
193198
// init crc
194199
uint16_t crc = ~0;
195-
for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
196-
crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET);
200+
for (uint32_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
201+
crc ^= _flash_readByte(i + FIRMWARE_START_OFFSET);
197202
for (int8_t j = 0; j < 8; ++j) {
198203
if (crc & 1) {
199204
crc = (crc >> 1) ^ 0xA001;
@@ -207,3 +212,76 @@ LOCAL bool transportIsValidFirmware(void)
207212
_nodeFirmwareConfig.crc);
208213
return crc == _nodeFirmwareConfig.crc;
209214
}
215+
216+
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data)
217+
{
218+
if (_firmwareUpdateOngoing) {
219+
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block
220+
if (block != _firmwareBlock - 1) {
221+
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
222+
// wrong firmware block received
223+
setIndication(INDICATION_FW_UPDATE_RX_ERR);
224+
// no further processing required
225+
return true;
226+
}
227+
setIndication(INDICATION_FW_UPDATE_RX);
228+
// Save block to flash
229+
#ifdef MCUBOOT_PRESENT
230+
uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)(
231+
FIRMWARE_START_OFFSET));
232+
if (addr<FLASH_AREA_IMAGE_SCRATCH_OFFSET_0) {
233+
Flash.write_block( (uint32_t *)addr, (uint32_t *)data, FIRMWARE_BLOCK_SIZE>>2);
234+
}
235+
#else
236+
_flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
237+
data, FIRMWARE_BLOCK_SIZE);
238+
#endif
239+
// wait until flash written
240+
while (_flash_busy()) {}
241+
#ifdef OTA_EXTRA_FLASH_DEBUG
242+
{
243+
char prbuf[8];
244+
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
245+
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
246+
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
247+
MY_SERIALDEVICE.print(prbuf);
248+
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
249+
uint8_t data = _flash_readByte(addr + i);
250+
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
251+
MY_SERIALDEVICE.print(prbuf);
252+
}
253+
OTA_DEBUG(PSTR("\n"));
254+
}
255+
#endif
256+
_firmwareBlock--;
257+
if (!_firmwareBlock) {
258+
// We're done! Do a checksum and reboot.
259+
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
260+
_firmwareUpdateOngoing = false;
261+
if (transportIsValidFirmware()) {
262+
OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
263+
// Write the new firmware config to eeprom
264+
hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
265+
sizeof(nodeFirmwareConfig_t));
266+
#ifndef MCUBOOT_PRESENT
267+
// All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
268+
const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks;
269+
const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'};
270+
_flash_writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
271+
// wait until flash ready
272+
while (_flash_busy()) {}
273+
#endif
274+
hwReboot();
275+
} else {
276+
setIndication(INDICATION_ERR_FW_CHECKSUM);
277+
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
278+
}
279+
}
280+
// reset flags
281+
_firmwareRetry = MY_OTA_RETRY + 1;
282+
_firmwareLastRequest = 0;
283+
} else {
284+
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
285+
}
286+
return true;
287+
}

0 commit comments

Comments
 (0)