diff options
Diffstat (limited to 'arduino/cores/nRF5/flash/flash_cache.c')
-rwxr-xr-x | arduino/cores/nRF5/flash/flash_cache.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/arduino/cores/nRF5/flash/flash_cache.c b/arduino/cores/nRF5/flash/flash_cache.c new file mode 100755 index 0000000..09126f3 --- /dev/null +++ b/arduino/cores/nRF5/flash/flash_cache.c @@ -0,0 +1,141 @@ +/**************************************************************************/ +/*! + @file flash_cache.c + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#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); +} + +uint32_t 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 + 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; +} + +void flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count) +{ + // overwrite with cache value if available + if ( (fc->cache_addr != FLASH_CACHE_INVALID_ADDR) && + !(addr < fc->cache_addr && addr + count <= fc->cache_addr) && + !(addr >= fc->cache_addr + FLASH_CACHE_SIZE) ) + { + int dst_off = fc->cache_addr - addr; + int src_off = 0; + + if ( dst_off < 0 ) + { + src_off = -dst_off; + dst_off = 0; + } + + int cache_bytes = minof(FLASH_CACHE_SIZE-src_off, count - dst_off); + + // start to cached + if ( dst_off ) fc->read(dst, addr, dst_off); + + // cached + memcpy(dst + dst_off, fc->cache_buf + src_off, cache_bytes); + + // cached to end + int copied = dst_off + cache_bytes; + if ( copied < count ) fc->read(dst + copied, addr + copied, count - copied); + } + else + { + fc->read(dst, (void*) addr, count); + } +} |