diff --git a/Config.h b/Config.h index 43cb29b..5827e7d 100644 --- a/Config.h +++ b/Config.h @@ -316,8 +316,9 @@ #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_SIZE 6144 #define CONFIG_QUEUE_MAX_LENGTH 200 - #define EEPROM_SIZE 4096 - #define EEPROM_OFFSET EEPROM_SIZE+0xED000-EEPROM_RESERVED + #define EEPROM_SIZE 200 + //#define EEPROM_OFFSET EEPROM_SIZE+0xED000-EEPROM_RESERVED + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED // following pins are for the sx1262 const int pin_rxen = 37; diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 05acd1a..ce1d2ef 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -54,6 +54,12 @@ void setup() { Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); #endif + #if MCU_VARIANT == MCU_NRF52 + if (!eeprom_begin()) { + Serial.write("EEPROM initialisation failed.\r\n"); + } + #endif + // Seed the PRNG randomSeed(analogRead(0)); diff --git a/Utilities.h b/Utilities.h index fe61b7c..d6cfdc9 100644 --- a/Utilities.h +++ b/Utilities.h @@ -18,8 +18,13 @@ #if HAS_EEPROM #include #elif PLATFORM == PLATFORM_NRF52 - #include "flash_nrf5x.h" - int written_bytes = 0; + #include + #include + using namespace Adafruit_LittleFS_Namespace; + #define EEPROM_FILE "eeprom" + bool file_exists = false; + int written_bytes = 4; + File file(InternalFS); #endif #include #include "LoRa.h" @@ -1093,10 +1098,33 @@ void promisc_disable() { } #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + bool eeprom_begin() { + InternalFS.begin(); + + file.open(EEPROM_FILE, FILE_O_READ); + + // if file doesn't exist + if (!file) { + if (file.open(EEPROM_FILE, FILE_O_WRITE)) { + // initialise the file with empty content + uint8_t empty_content[EEPROM_SIZE] = {0}; + file.write(empty_content, EEPROM_SIZE); + return true; + } else { + return false; + } + } else { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + return true; + } + } + uint8_t eeprom_read(uint32_t mapped_addr) { uint8_t byte; void* byte_ptr = &byte; - flash_nrf5x_read(byte_ptr, mapped_addr, 1); + file.seek(mapped_addr); + file.read(byte_ptr, 1); return byte; } #endif @@ -1165,18 +1193,18 @@ void eeprom_update(int mapped_addr, uint8_t byte) { #elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 uint8_t read_byte; void* read_byte_ptr = &read_byte; - void const * byte_ptr = &byte; - flash_nrf5x_read(read_byte_ptr, mapped_addr, 1); + file.seek(mapped_addr); + file.read(read_byte_ptr, 1); + file.seek(mapped_addr); if (read_byte != byte) { - flash_nrf5x_write(mapped_addr, byte_ptr, 1); + file.write(byte); } - written_bytes++; - // flush the cache every 4 bytes to make sure everything is synced - if (written_bytes == 4) { + if (written_bytes >= 8) { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); written_bytes = 0; - flash_nrf5x_flush(); } #endif diff --git a/flash_cache.c b/flash_cache.c deleted file mode 100644 index 50d69f7..0000000 --- a/flash_cache.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifdef NRF52840_XXAA -#include -#include "flash_cache.h" -#include "common_func.h" -#include "variant.h" -#include "wiring_digital.h" - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ -static inline uint32_t page_addr_of (uint32_t addr) -{ - return addr & ~(FLASH_CACHE_SIZE - 1); -} - -static inline uint32_t page_offset_of (uint32_t addr) -{ - return addr & (FLASH_CACHE_SIZE - 1); -} - -int flash_cache_write (flash_cache_t* fc, uint32_t dst, void const * src, uint32_t len) -{ - uint8_t const * src8 = (uint8_t const *) src; - uint32_t remain = len; - - // Program up to page boundary each loop - while ( remain ) - { - uint32_t const page_addr = page_addr_of(dst); - uint32_t const offset = page_offset_of(dst); - - uint32_t wr_bytes = FLASH_CACHE_SIZE - offset; - wr_bytes = min32(remain, wr_bytes); - - // Page changes, flush old and update new cache - if ( page_addr != fc->cache_addr ) - { - flash_cache_flush(fc); - fc->cache_addr = page_addr; - - // read a whole page from flash - fc->read(fc->cache_buf, page_addr, FLASH_CACHE_SIZE); - } - - memcpy(fc->cache_buf + offset, src8, wr_bytes); - - // adjust for next run - src8 += wr_bytes; - remain -= wr_bytes; - dst += wr_bytes; - } - - return len - remain; -} - -void flash_cache_flush (flash_cache_t* fc) -{ - if ( fc->cache_addr == FLASH_CACHE_INVALID_ADDR ) return; - - // skip erase & program if verify() exists, and memory matches - if ( !(fc->verify && fc->verify(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE)) ) - { - // indicator TODO allow to disable flash indicator - ledOn(LED_BUILTIN); - - fc->erase(fc->cache_addr); - fc->program(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE); - - ledOff(LED_BUILTIN); - } - - fc->cache_addr = FLASH_CACHE_INVALID_ADDR; -} - -int flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count) -{ - // there is no check for overflow / wraparound for dst + count, addr + count. - // this might be a useful thing to add for at least debug builds. - - // overwrite with cache value if available - if ( (fc->cache_addr != FLASH_CACHE_INVALID_ADDR) && // cache is not valid - !(addr < fc->cache_addr && addr + count <= fc->cache_addr) && // starts before, ends before cache area - !(addr >= fc->cache_addr + FLASH_CACHE_SIZE) ) // starts after end of cache area - { - // This block is entered only when the read overlaps the cache area by at least one byte. - // If the read starts before the cache area, it's further guaranteed - // that count is large enough to cause the read to enter - // the cache area by at least 1 byte. - uint32_t dst_off = 0; - uint32_t src_off = 0; - if (addr < fc->cache_addr) - { - dst_off = fc->cache_addr - addr; - // Read the bytes prior to the cache address - fc->read(dst, addr, dst_off); - } - else - { - src_off = addr - fc->cache_addr; - } - - // Thus, after the above code block executes: - // *** AT MOST ***, only one of src_off and dst_off are non-zero; - // (Both may be zero when the read starts at the start of the cache area.) - // dst_off corresponds to the number of bytes already read from PRIOR to the cache area. - // src_off corresponds to the byte offset to start reading at, from WITHIN the cache area. - - // How many bytes to memcpy from flash area? - // Remember that, AT MOST, one of src_off and dst_off are non-zero. - // If src_off is non-zero, then dst_off is zero, representing that the - // read starts inside the cache. In this case: - // PARAM1 := FLASH_CACHE_SIZE - src_off == maximum possible bytes to read from cache - // PARAM2 := count - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE-src_off ]. - // Else if dst_off is non-zero, then src_off is zero, representing that the - // read started prior to the cache area. In this case: - // PARAM1 := FLASH_CACHE_SIZE == full size of the cache - // PARAM2 := count - dst_off == total bytes requested, minus the count of those already read - // Because the original request is guaranteed to overlap the cache, the range for - // PARAM2 is ensured to be [ 1 .. count-1 ]. - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE ] - // Else both src_off and dst_off are zero, representing that the read is starting - // exactly aligned to the cache. - // PARAM1 := FLASH_CACHE_SIZE - // PARAM2 := count - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE ] - // - // Therefore, in all cases, there is assurance that cache_bytes - // will be in the final range [1..FLASH_CACHE_SIZE]. - uint32_t cache_bytes = minof(FLASH_CACHE_SIZE-src_off, count - dst_off); - - // Use memcpy to read cached data into the buffer - // If src_off is non-zero, then dst_off is zero, representing that the - // read starts inside the cache. In this case: - // PARAM1 := dst - // PARAM2 := fc->cache_buf + src_off - // PARAM3 := cache_bytes - // Thus, all works as expected when starting in the midst of the cache. - // Else if dst_off is non-zero, then src_off is zero, representing that the - // read started prior to the cache. In this case: - // PARAM1 := dst + dst_off == destination offset by number of bytes already read - // PARAM2 := fc->cache_buf - // PARAM3 := cache_bytes - // Thus, all works as expected when starting prior to the cache. - // Else both src_off and dst_off are zero, representing that the read is starting - // exactly aligned to the cache. - // PARAM1 := dst - // PARAM2 := fc->cache_buf - // PARAM3 := cache_bytes - // Thus, all works as expected when starting exactly at the cache boundary - // - // Therefore, in all cases, there is assurance that cache_bytes - // will be in the final range [1..FLASH_CACHE_SIZE]. - memcpy(dst + dst_off, fc->cache_buf + src_off, cache_bytes); - - // Read any final bytes from flash - // As noted above, dst_off represents the count of bytes read prior to the cache - // while cache_bytes represents the count of bytes read from the cache; - // This code block is guaranteed to overlap the cache area by at least one byte. - // Thus, copied will correspond to the total bytes already copied, - // and is guaranteed to be in the range [ 1 .. count ]. - uint32_t copied = dst_off + cache_bytes; - - // - if ( copied < count ) - { - fc->read(dst + copied, addr + copied, count - copied); - } - } - else - { - // not using the cache, so just forward to read from flash - fc->read(dst, addr, count); - } - - return (int) count; -} -#endif diff --git a/flash_cache.h b/flash_cache.h deleted file mode 100644 index ff585e5..0000000 --- a/flash_cache.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifdef NRF52840_XXAA -#ifndef FLASH_CACHE_H_ -#define FLASH_CACHE_H_ - -#include -#include - -#define FLASH_CACHE_SIZE 4096 // must be a erasable page size -#define FLASH_CACHE_INVALID_ADDR 0xffffffff - -typedef struct -{ - bool (*erase) (uint32_t addr); - uint32_t (*program) (uint32_t dst, void const * src, uint32_t len); - uint32_t (*read) (void* dst, uint32_t src, uint32_t len); - bool (*verify) (uint32_t addr, void const * buf, uint32_t len); - - uint32_t cache_addr; - uint8_t* cache_buf; -} flash_cache_t; - -#ifdef __cplusplus -extern "C" { -#endif - -int flash_cache_write (flash_cache_t* fc, uint32_t dst, void const *src, uint32_t count); -void flash_cache_flush (flash_cache_t* fc); -int flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count); - -#ifdef __cplusplus - } -#endif - -#endif /* FLASH_CACHE_H_ */ -#endif diff --git a/flash_nrf5x.c b/flash_nrf5x.c deleted file mode 100644 index 0442a39..0000000 --- a/flash_nrf5x.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifdef NRF52840_XXAA -#include "flash_nrf5x.h" -#include "flash_cache.h" -#include "nrf_sdm.h" -#include "nrf_soc.h" -#include "delay.h" -#include "rtos.h" - - -#ifdef NRF52840_XXAA - #define BOOTLOADER_ADDR 0xF4000 -#else - #define BOOTLOADER_ADDR 0x74000 -#endif - -// defined in linker script -extern uint32_t __flash_arduino_start[]; -//extern uint32_t __flash_arduino_end[]; - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ -static SemaphoreHandle_t _sem = NULL; - -void flash_nrf5x_event_cb (uint32_t event) -{ -// if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed"); - if ( _sem ) xSemaphoreGive(_sem); -} - -// Flash Abstraction Layer -static bool fal_erase (uint32_t addr); -static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len); -static uint32_t fal_read (void* dst, uint32_t src, uint32_t len); -static bool fal_verify (uint32_t addr, void const * buf, uint32_t len); - -static uint8_t _cache_buffer[FLASH_CACHE_SIZE] __attribute__((aligned(4))); - -static flash_cache_t _cache = -{ - .erase = fal_erase, - .program = fal_program, - .read = fal_read, - .verify = fal_verify, - - .cache_addr = FLASH_CACHE_INVALID_ADDR, - .cache_buf = _cache_buffer -}; - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ -void flash_nrf5x_flush (void) -{ - flash_cache_flush(&_cache); -} - -int flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len) -{ - // Softdevice region - VERIFY(dst >= ((uint32_t) __flash_arduino_start), -1); - - // Bootloader region - VERIFY(dst < BOOTLOADER_ADDR, -1); - - return flash_cache_write(&_cache, dst, src, len); -} - -int flash_nrf5x_read (void* dst, uint32_t src, uint32_t len) -{ - return flash_cache_read(&_cache, dst, src, len); -} - -bool flash_nrf5x_erase(uint32_t addr) -{ - return fal_erase(addr); -} - -//--------------------------------------------------------------------+ -// HAL for caching -//--------------------------------------------------------------------+ -static bool fal_erase (uint32_t addr) -{ - // Init semaphore for first call - if ( _sem == NULL ) - { - _sem = xSemaphoreCreateCounting(10, 0); - VERIFY(_sem); - } - - // retry if busy - uint32_t err; - while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) ) - { - delay(1); - } - VERIFY_STATUS(err, false); - - // wait for async event if SD is enabled - uint8_t sd_en = 0; - (void) sd_softdevice_is_enabled(&sd_en); - - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); - - return true; -} - -static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len) -{ - // wait for async event if SD is enabled - uint8_t sd_en = 0; - (void) sd_softdevice_is_enabled(&sd_en); - - uint32_t err; - - // Somehow S140 v6.1.1 assert an error when writing a whole page - // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert - // Workaround: write half page at a time. -#if NRF52832_XXAA - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); -#else - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); - - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); -#endif - - return len; -} - -static uint32_t fal_read (void* dst, uint32_t src, uint32_t len) -{ - memcpy(dst, (void*) src, len); - return len; -} - -static bool fal_verify (uint32_t addr, void const * buf, uint32_t len) -{ - return 0 == memcmp((void*) addr, buf, len); -} -#endif diff --git a/flash_nrf5x.h b/flash_nrf5x.h deleted file mode 100644 index 138cf9c..0000000 --- a/flash_nrf5x.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifdef NRF52840_XXAA -#ifndef FLASH_NRF52_H_ -#define FLASH_NRF52_H_ - -#include "common_inc.h" - -#define FLASH_NRF52_PAGE_SIZE 4096 - -#ifdef __cplusplus - extern "C" { -#endif - -void flash_nrf5x_flush (void); -bool flash_nrf5x_erase(uint32_t addr); - -int flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len); -int flash_nrf5x_read (void* dst, uint32_t src, uint32_t len); - -//--------------------------------------------------------------------+ -// Write helper -//--------------------------------------------------------------------+ -static inline int flash_nrf5x_write8 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} - -static inline int flash_nrf5x_write16 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} -static inline int flash_nrf5x_write32 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} - -//--------------------------------------------------------------------+ -// Read helper -//--------------------------------------------------------------------+ -static inline uint8_t flash_nrf5x_read8 (uint32_t src) -{ - uint8_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - -static inline uint16_t flash_nrf5x_read16 (uint32_t src) -{ - uint16_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - -static inline uint16_t flash_nrf5x_read32 (uint32_t src) -{ - uint32_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - - -#ifdef __cplusplus - } -#endif - -#endif /* FLASH_NRF52_H_ */ -#endif