mirror of
https://github.com/mysensors/MySensors.git
synced 2026-02-20 01:21:27 +01:00
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
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user