* 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
This commit is contained in:
d00616
2018-02-28 20:03:34 +01:00
committed by Mikael Falkvidd
parent 599c0bada6
commit fe42dbdcca
9 changed files with 292 additions and 106 deletions
+18
View File
@@ -1654,6 +1654,23 @@
#define MY_SIGNING_SOFT_RANDOMSEED_PIN (7)
#endif
/**
* @def MY_LOCK_DEVICE
* @brief Enable read back protection
*
* Enable read back protection feature. Currently only supported by NRF51+NRF52.
* Use this flag to protect signing and encryption keys stored in the MCU.
*
* Set this flag, when you use softsigning in MySensors. Don't set this
* in SecurityPersonalizer.
*
* @warning YOU CAN BRICK YOUR DEVICE!!!
* Don't set this flag without having an boot loader, OTA firmware update and
* an Gateway connection. To reset an device, you can try >>
* openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c "program dap apreg 1 0x04 0x01"
*/
//#define MY_LOCK_DEVICE
/**
* @def MY_SIGNING_FEATURE
* @ingroup internals
@@ -2023,6 +2040,7 @@
#define MY_INDICATION_HANDLER
#define MY_DISABLE_REMOTE_RESET
#define MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
#define MY_LOCK_DEVICE
// core
#define MY_CORE_ONLY
// GW
+2
View File
@@ -126,11 +126,13 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
// FLASH
#if defined(MY_OTA_FIRMWARE_FEATURE)
#ifndef MCUBOOT_PRESENT
#if defined(MY_OTA_USE_I2C_EEPROM)
#include "drivers/I2CEeprom/I2CEeprom.cpp"
#else
#include "drivers/SPIFlash/SPIFlash.cpp"
#endif
#endif
#include "core/MyOTAFirmwareUpdate.cpp"
#endif
+3 -1
View File
@@ -208,7 +208,9 @@ typedef enum {
ST_FIRMWARE_REQUEST = 2, //!< Request FW block
ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
ST_SOUND = 4, //!< Sound
ST_IMAGE = 5 //!< Image
ST_IMAGE = 5, //!< Image
ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data
} mysensor_stream;
/// @brief Type of payload
+144 -66
View File
@@ -26,15 +26,30 @@ extern MyMessage _msgTmp;
// local variables
#ifdef MY_OTA_USE_I2C_EEPROM
I2CEeprom _flash(MY_OTA_I2C_ADDR);
#else
#elif !defined(MCUBOOT_PRESENT)
SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
#endif
// Map flash functions
#ifndef MCUBOOT_PRESENT
#define _flash_initialize() _flash.initialize()
#define _flash_readByte(addr) _flash.readByte(addr)
#define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size)
#define _flash_blockErase32K(num) _flash.blockErase32K(num)
#define _flash_busy() _flash.busy()
#else
#define _flash_initialize() true
#define _flash_readByte(addr) (*((uint8_t *)(addr)))
#define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0)
#define _flash_busy() false
#endif
LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig;
LOCAL bool _firmwareUpdateOngoing = false;
LOCAL uint32_t _firmwareLastRequest;
LOCAL uint16_t _firmwareBlock;
LOCAL uint8_t _firmwareRetry;
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data);
LOCAL void readFirmwareSettings(void)
{
@@ -83,15 +98,15 @@ LOCAL bool firmwareOTAUpdateProcess(void)
// copy new FW config
(void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
// Init flash
if (!_flash.initialize()) {
if (!_flash_initialize()) {
setIndication(INDICATION_ERR_FW_FLASH_INIT);
OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
_firmwareUpdateOngoing = false;
} else {
// erase lower 32K -> max flash size for ATMEGA328
_flash.blockErase32K(0);
_flash_blockErase32K(0);
// wait until flash erased
while ( _flash.busy() ) {}
while ( _flash_busy() ) {}
_firmwareBlock = _nodeFirmwareConfig.blocks;
_firmwareUpdateOngoing = true;
// reset flags
@@ -102,68 +117,46 @@ LOCAL bool firmwareOTAUpdateProcess(void)
}
OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
if (_firmwareUpdateOngoing) {
// extract FW block
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), firmwareResponse->block); // received FW block
if (firmwareResponse->block != _firmwareBlock - 1) {
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
// wrong firmware block received
setIndication(INDICATION_FW_UPDATE_RX_ERR);
// no further processing required
return true;
}
setIndication(INDICATION_FW_UPDATE_RX);
// Save block to flash
_flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
// wait until flash written
while (_flash.busy()) {}
#ifdef OTA_EXTRA_FLASH_DEBUG
{
char prbuf[8];
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
MY_SERIALDEVICE.print(prbuf);
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
uint8_t data = _flash.readByte(addr + i);
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
MY_SERIALDEVICE.print(prbuf);
}
OTA_DEBUG(PSTR("\n"));
}
#endif
_firmwareBlock--;
if (!_firmwareBlock) {
// We're done! Do a checksum and reboot.
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
_firmwareUpdateOngoing = false;
if (transportIsValidFirmware()) {
OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
// Write the new firmware config to eeprom
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);
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
}
}
// reset flags
_firmwareRetry = MY_OTA_RETRY + 1;
_firmwareLastRequest = 0;
} else {
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
// extract FW block
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
// Proceed firmware data
return _firmwareResponse(firmwareResponse->block, firmwareResponse->data);
#ifdef FIRMWARE_PROTOCOL_31
} else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) {
// RLE encoded block
// extract FW block
replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data;
uint8_t data[FIRMWARE_BLOCK_SIZE];
for (uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
data[i]=firmwareResponse->data;
}
while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) {
_firmwareResponse(firmwareResponse->block, data);
firmwareResponse->number_of_blocks--;
firmwareResponse->block--;
}
return true;
#endif
} else {
#ifdef MCUBOOT_PRESENT
if (_msg.type == ST_FIRMWARE_CONFIRM) {
if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) {
if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) {
// Calculate data word to write
uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise
uint32_t img_ok_data = *img_ok_base_addr;
// Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01)
uint8_t * img_ok_array = (uint8_t*)(&img_ok_data);
img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE;
// Write word back
Flash.write(img_ok_base_addr, img_ok_data);
}
OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n"));
} else {
OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n"));
}
}
#endif
}
return false;
}
@@ -178,6 +171,18 @@ LOCAL void presentBootloaderInformation(void)
(void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t));
// add bootloader information
requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
#ifdef FIRMWARE_PROTOCOL_31
requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE;
#ifndef MCUBOOT_PRESENT
requestFirmwareConfig->img_commited = 0x2;
requestFirmwareConfig->img_revision = 0x00;
requestFirmwareConfig->img_build_num = 0x00;
#else
requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR));
requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR));
requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR));
#endif
#endif
_firmwareUpdateOngoing = false;
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
ST_FIRMWARE_CONFIG_REQUEST, false));
@@ -192,8 +197,8 @@ LOCAL bool transportIsValidFirmware(void)
{
// init crc
uint16_t crc = ~0;
for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET);
for (uint32_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;
@@ -207,3 +212,76 @@ LOCAL bool transportIsValidFirmware(void)
_nodeFirmwareConfig.crc);
return crc == _nodeFirmwareConfig.crc;
}
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data)
{
if (_firmwareUpdateOngoing) {
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block
if (block != _firmwareBlock - 1) {
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
// wrong firmware block received
setIndication(INDICATION_FW_UPDATE_RX_ERR);
// no further processing required
return true;
}
setIndication(INDICATION_FW_UPDATE_RX);
// Save block to flash
#ifdef MCUBOOT_PRESENT
uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)(
FIRMWARE_START_OFFSET));
if (addr<FLASH_AREA_IMAGE_SCRATCH_OFFSET_0) {
Flash.write_block( (uint32_t *)addr, (uint32_t *)data, FIRMWARE_BLOCK_SIZE>>2);
}
#else
_flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
data, FIRMWARE_BLOCK_SIZE);
#endif
// wait until flash written
while (_flash_busy()) {}
#ifdef OTA_EXTRA_FLASH_DEBUG
{
char prbuf[8];
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
MY_SERIALDEVICE.print(prbuf);
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
uint8_t data = _flash_readByte(addr + i);
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
MY_SERIALDEVICE.print(prbuf);
}
OTA_DEBUG(PSTR("\n"));
}
#endif
_firmwareBlock--;
if (!_firmwareBlock) {
// We're done! Do a checksum and reboot.
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
_firmwareUpdateOngoing = false;
if (transportIsValidFirmware()) {
OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
// Write the new firmware config to eeprom
hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
sizeof(nodeFirmwareConfig_t));
#ifndef MCUBOOT_PRESENT
// 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()) {}
#endif
hwReboot();
} else {
setIndication(INDICATION_ERR_FW_CHECKSUM);
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
}
}
// reset flags
_firmwareRetry = MY_OTA_RETRY + 1;
_firmwareLastRequest = 0;
} else {
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
}
return true;
}
+47
View File
@@ -58,17 +58,36 @@
#define MyOTAFirmwareUpdate_h
#include "MySensorsCore.h"
#ifdef MCUBOOT_PRESENT
#include "generated_dts_board.h"
#define FIRMWARE_PROTOCOL_31
#endif
#define LOCAL static //!< static
#if MAX_PAYLOAD >= 22
#define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block
#else
#define FIRMWARE_BLOCK_SIZE (8u) //!< Size of each firmware block
#ifndef FIRMWARE_PROTOCOL_31
#define FIRMWARE_PROTOCOL_31
#endif
#endif
#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
#ifndef MCUBOOT_PRESENT
#define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first)
#else
#define FIRMWARE_START_OFFSET (FLASH_AREA_IMAGE_1_OFFSET_0) //!< Use offset from generated_dts_board.h (mcuboot)
#endif
#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major
#ifdef FIRMWARE_PROTOCOL_31
#define MY_OTA_BOOTLOADER_MINOR_VERSION (1u) //!< Bootloader version minor
#else
#define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor
#endif
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version
#if defined(MY_DEBUG_VERBOSE_OTA_UPDATE)
@@ -77,6 +96,18 @@
#else
#define OTA_DEBUG(x,...) //!< debug NULL
#endif
#if defined(DOXYGEN) && !defined(FIRMWARE_PROTOCOL_31)
/**
* @brief Enabled FOTA 3.1 protocol extensions
*
* Supports smaller FIRMWARE_BLOCK_SIZE, RLE and NVM for nRF5 with mcuboot. The
* extension is enabled per default when mcuboot is present or full FIRMWARE_BLOCK_SIZE
* exeeds MAX_PAYLOAD.
*/
#define FIRMWARE_PROTOCOL_31
#endif
/**
* @brief FW config structure, stored in eeprom
*/
@@ -96,6 +127,12 @@ typedef struct {
uint16_t blocks; //!< Number of blocks
uint16_t crc; //!< CRC of block data
uint16_t BLVersion; //!< Bootloader version
#ifdef FIRMWARE_PROTOCOL_31
uint8_t blockSize; //!< Blocksize, when protocol version >= 3.1 is reported. Otherwhise the blocksize is 16
uint8_t img_commited; //!< mcuboot image_ok attribute commited firmware=0x01(mcuboot)|0x02(DualOptiboot), when protocol version >= 3.1 is reported
uint16_t img_revision; //!< mcuboot revision attribute, when protocol version >= 3.1 is reported
uint32_t img_build_num; //!< mcuboot build_num attribute, when protocol version >= 3.1 is reported
#endif
} __attribute__((packed)) requestFirmwareConfig_t;
/**
@@ -117,6 +154,16 @@ typedef struct {
uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data
} __attribute__((packed)) replyFirmwareBlock_t;
/**
* @brief FW block reply structure (RLE)
*/
typedef struct {
uint16_t type; //!< Type of config
uint16_t version; //!< Version of config
uint16_t block; //!< Block index
uint16_t number_of_blocks; //!< Number of blocks to fill with data
uint8_t data; //!< Block data
} __attribute__((packed)) replyFirmwareBlockRLE_t;
/**
* @brief Read firmware settings from EEPROM
+2
View File
@@ -52,12 +52,14 @@ uint32_t *FlashClass::page_address(size_t page)
uint32_t *FlashClass::top_app_page_address()
{
#if !defined(MCUBOOT_PRESENT)
// Bootcode at the top of the flash memory?
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Flib_bootloader.html
if (NRF_UICR->NRFFW[0]<0xFFFFFFFF) {
// Return pointer calculated by SoftDevice/bootloader
return (uint32_t *)NRF_UICR->NRFFW[0];
}
#endif
// Return flash length
return (uint32_t *)(Flash.page_count() << Flash.page_size_bits());
+47 -39
View File
@@ -21,37 +21,45 @@
VirtualPageClass VirtualPage;
#ifndef VNM_VIRTUAL_PAGE_SIZE_BITS
#define VNM_VIRTUAL_PAGE_SIZE_BITS 12
#elif VNM_VIRTUAL_PAGE_SIZE_BITS < 12
#error "VNM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
#ifndef NVM_VIRTUAL_PAGE_SIZE_BITS
#define NVM_VIRTUAL_PAGE_SIZE_BITS 12
#elif NVM_VIRTUAL_PAGE_SIZE_BITS < 12
#error "NVM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
#endif
// Calculate virtual page count, when mcuboot is present
#if defined(MCUBOOT_PRESENT) && !defined(NVM_VIRTUAL_PAGE_COUNT)
// mcuboot zephyr build via generated_dts_board.h
#include "generated_dts_board.h"
// Calculate number of free pages after scratch area
#define NVM_VIRTUAL_PAGE_COUNT (((CONFIG_FLASH_SIZE_0<<10)-(FLASH_AREA_IMAGE_SCRATCH_OFFSET_0+FLASH_AREA_IMAGE_SCRATCH_SIZE_0)) >> NVM_VIRTUAL_PAGE_SIZE_BITS)
#endif
// check page size
#ifndef VNM_VIRTUAL_PAGE_COUNT
#ifndef NVM_VIRTUAL_PAGE_COUNT
#if FLASH_ERASE_CYCLES >= 20000
// use 16k of flash memory
#define VNM_VIRTUAL_PAGE_COUNT 4
#define NVM_VIRTUAL_PAGE_COUNT 4
#else
// use 32k of flash memory
#define VNM_VIRTUAL_PAGE_COUNT 8
#define NVM_VIRTUAL_PAGE_COUNT 8
#endif
#endif
/*
* How many virtual pages are skipped from top of flash
*/
#ifndef VNM_VIRTUAL_PAGE_SKIP_FROM_TOP
#define VNM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
#ifndef NVM_VIRTUAL_PAGE_SKIP_FROM_TOP
#define NVM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
#endif
/*
* Calculate things around VNM_VIRTUAL_PAGE_SIZE
* Calculate things around NVM_VIRTUAL_PAGE_SIZE
*/
#define VNM_VIRTUAL_PAGE_SIZE (1 << (VNM_VIRTUAL_PAGE_SIZE_BITS))
#define VNM_VIRTUAL_PAGE_ADDRESS_MASK (~(VNM_VIRTUAL_PAGE_SIZE - 1))
#define VNM_VIRTUAL_PAGE_ALIGN(address) \
{ address = (uint32_t *)((uint32_t)address & VNM_VIRTUAL_PAGE_ADDRESS_MASK); }
#define NVM_VIRTUAL_PAGE_SIZE (1 << (NVM_VIRTUAL_PAGE_SIZE_BITS))
#define NVM_VIRTUAL_PAGE_ADDRESS_MASK (~(NVM_VIRTUAL_PAGE_SIZE - 1))
#define NVM_VIRTUAL_PAGE_ALIGN(address) \
{ address = (uint32_t *)((uint32_t)address & NVM_VIRTUAL_PAGE_ADDRESS_MASK); }
/*
* Defines the position of status words in a page.
@@ -79,8 +87,8 @@ VirtualPageClass VirtualPage;
#define OFFSET_MAGIC 1
#define OFFSET_COUNTER 0
#define MASK_ERASE_COUNTER 0x00FFFFFF
#define OFFSET_STATUS_RELEASE_PREPARE VNM_VIRTUAL_PAGE_SIZE - 8
#define OFFSET_STATUS_RELEASE_END VNM_VIRTUAL_PAGE_SIZE - 4
#define OFFSET_STATUS_RELEASE_PREPARE NVM_VIRTUAL_PAGE_SIZE - 8
#define OFFSET_STATUS_RELEASE_END NVM_VIRTUAL_PAGE_SIZE - 4
#define METADATA_SIZE 16
#define OFFSET_DATA 4
#endif
@@ -88,45 +96,45 @@ VirtualPageClass VirtualPage;
#define BIT_STATUS_RELEASE_PREPARE (1 << 30)
#define BIT_STATUS_RELEASE_END (1 << 31)
#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
#else
// use first 8 byte for magic and erase counter and last 8 byte for page release
#define OFFSET_MAGIC 1
#define OFFSET_ERASE_COUNTER 0
#define OFFSET_DATA 2
#define OFFSET_STATUS_RELEASE_PREPARE \
((VNM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
((NVM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
#define OFFSET_STATUS_RELEASE_END \
((VNM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
((NVM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
#define MASK_ERASE_COUNTER 0xFFFFFFFF
#define BIT_STATUS_RELEASE_PREPARE 1
#define BIT_STATUS_RELEASE_END 1
#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - 16)
#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - 16)
#endif
uint16_t VirtualPageClass::size() const
{
return (VNM_VIRTUAL_PAGE_DATA_SIZE);
return (NVM_VIRTUAL_PAGE_DATA_SIZE);
}
uint16_t VirtualPageClass::length() const
{
return (VNM_VIRTUAL_PAGE_DATA_SIZE / 4);
return (NVM_VIRTUAL_PAGE_DATA_SIZE / 4);
}
uint16_t VirtualPageClass::page_count() const
{
return (VNM_VIRTUAL_PAGE_COUNT - 1);
return (NVM_VIRTUAL_PAGE_COUNT - 1);
}
uint32_t VirtualPageClass::wear_level()
{
uint32_t max_erase_cycles = 0;
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t erase_cycles = get_page_erase_cycles(get_page_address(i));
if (erase_cycles > max_erase_cycles) {
max_erase_cycles = erase_cycles;
@@ -140,7 +148,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
{
// Give back a page prepared for release and not closed
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -156,7 +164,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
}
// check if a unreleased page is available
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -177,7 +185,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic)
uint32_t max_erase_cycles = (uint32_t)~0;
// Avoid duplicate allocation of pages, look for the less used page
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
// Delete duplicated pages
@@ -225,7 +233,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic, uint32_t max_writes)
void VirtualPageClass::release_prepare(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -244,7 +252,7 @@ void VirtualPageClass::release_prepare(uint32_t *address)
void VirtualPageClass::release(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -263,7 +271,7 @@ void VirtualPageClass::release(uint32_t *address)
bool VirtualPageClass::release_started(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
return (address[OFFSET_STATUS_RELEASE_PREPARE] &
BIT_STATUS_RELEASE_PREPARE) == 0;
@@ -272,7 +280,7 @@ bool VirtualPageClass::release_started(uint32_t *address)
void VirtualPageClass::fail(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
build_page(address, 0x00000000);
return;
@@ -281,7 +289,7 @@ void VirtualPageClass::fail(uint32_t *address)
void VirtualPageClass::clean_up()
{
// No page found -> try to give back a page prepared for release
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if ((page[OFFSET_STATUS_RELEASE_END] & BIT_STATUS_RELEASE_END) == 0) {
build_page(get_page_address(i), ~0);
@@ -292,7 +300,7 @@ void VirtualPageClass::clean_up()
void VirtualPageClass::format()
{
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *address = get_page_address(i);
build_page(address, (uint32_t)~0);
}
@@ -301,25 +309,25 @@ void VirtualPageClass::format()
uint32_t *VirtualPageClass::get_page_address(uint16_t page)
{
return (uint32_t *)(Flash.top_app_page_address() -
((page + VNM_VIRTUAL_PAGE_SKIP_FROM_TOP)
<< VNM_VIRTUAL_PAGE_SIZE_BITS));
((page + NVM_VIRTUAL_PAGE_SKIP_FROM_TOP)
<< NVM_VIRTUAL_PAGE_SIZE_BITS));
}
void VirtualPageClass::build_page(uint32_t *address, uint32_t magic)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// get erase counter
uint32_t erase_counter = get_page_erase_cycles(address);
// Check if a magic is set
if (address[OFFSET_MAGIC] != (uint32_t)~0) {
Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
} else {
// check if page is empty
for (int i = OFFSET_DATA; i < (VNM_VIRTUAL_PAGE_SIZE / 4); i++) {
for (int i = OFFSET_DATA; i < (NVM_VIRTUAL_PAGE_SIZE / 4); i++) {
if (address[i] != (uint32_t)~0) {
Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
break;
}
}
@@ -234,6 +234,10 @@
#define GENERATE_SOMETHING
#endif
#if defined(MY_LOCK_MCU)
#undefine MY_LOCK_MCU // The Sketch after SecurityPersonaliter should lock the MCU
#endif
/********************************** Preprocessor sanitychecks *************************************/
#if defined(GENERATE_SOFT_SERIAL) && !defined(USE_SOFT_SIGNING)
#error Cannot generate soft serial using ATSHA204A, use USE_SOFT_SINGING for this
+25
View File
@@ -66,6 +66,31 @@ void hwWriteConfig(int adr, uint8_t value)
bool hwInit()
{
#ifdef MY_LOCK_MCU
#ifdef NRF51
// Lock MCU
if((uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos) !=
UICR_RBPCONF_PALL_Enabled) {
Flash.write((uint32_t *)&NRF_UICR->RBPCONF, (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk));
hwReboot();
}
#else
// Lock MCU
if((uint32_t)((NRF_UICR->APPROTECT & UICR_APPROTECT_PALL_Msk) >> UICR_APPROTECT_PALL_Pos) !=
UICR_APPROTECT_PALL_Enabled) {
Flash.write((uint32_t *)&NRF_UICR->APPROTECT, (NRF_UICR->APPROTECT & ~UICR_APPROTECT_PALL_Msk));
hwReboot();
}
#endif
#endif
#if defined(NRF51) && defined(CONFIG_ENABLE_PINRESET)
// Enabling reset for NRF51 isn't handled by arduino-nrf5. Enable it, if requested.
NRF_POWER->RESET = POWER_RESET_RESET_Enabled;
NRF_POWER->RAMON |= (POWER_RAMON_ONRAM0_RAM0On << POWER_RAMON_ONRAM0_Pos) |
(POWER_RAMON_ONRAM1_RAM1On << POWER_RAMON_ONRAM1_Pos);
#endif
// Clock is manged by sleep modes. Radio depends on HFCLK.
// Force to start HFCLK
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;