/* Copyright (c) 2017 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA WiFi101OTA version Feb 2017 by Sandeep Mistry (Arduino) modified for ArduinoOTA Dec 2018 by Juraj Andrassy */ #if !defined(__AVR__) && !defined(ESP8266) && !defined(ESP32) #include #include "InternalStorage.h" InternalStorageClass::InternalStorageClass() : MAX_PARTIONED_SKETCH_SIZE((MAX_FLASH - SKETCH_START_ADDRESS) / 2), STORAGE_START_ADDRESS(SKETCH_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE) { _writeIndex = 0; _writeAddress = nullptr; } extern "C" { // these functions must be in RAM (.data) and NOT inlined // as they erase and copy the sketch data in flash __attribute__ ((long_call, noinline, section (".data#"))) // void waitForReady() { #if defined(ARDUINO_ARCH_SAMD) while (!NVMCTRL->INTFLAG.bit.READY); #elif defined(ARDUINO_ARCH_NRF5) while (NRF_NVMC->READY == NVMC_READY_READY_Busy); #endif } __attribute__ ((long_call, noinline, section (".data#"))) static void eraseFlash(int address, int length, int pageSize) { #if defined(ARDUINO_ARCH_SAMD) int rowSize = pageSize * 4; for (int i = 0; i < length; i += rowSize) { NVMCTRL->ADDR.reg = ((uint32_t)(address + i)) / 2; NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; waitForReady(); } #elif defined(ARDUINO_ARCH_NRF5) // Enable erasing flash NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos; // Erase page(s) int end_address = address + length; while (address < end_address) { waitForReady(); // Erase one 1k/4k page NRF_NVMC->ERASEPAGE = address; address = address + pageSize; } // Disable erasing, enable write waitForReady(); NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; waitForReady(); #endif } __attribute__ ((long_call, noinline, section (".data#"))) static void copyFlashAndReset(int dest, int src, int length, int pageSize) { uint32_t* d = (uint32_t*)dest; uint32_t* s = (uint32_t*)src; eraseFlash(dest, length, pageSize); for (int i = 0; i < length; i += 4) { *d++ = *s++; waitForReady(); } NVIC_SystemReset(); } } int InternalStorageClass::open(int length) { (void)length; _writeIndex = 0; _writeAddress = (uint32_t*)STORAGE_START_ADDRESS; #ifdef ARDUINO_ARCH_SAMD // enable auto page writes NVMCTRL->CTRLB.bit.MANW = 0; #endif eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); return 1; } size_t InternalStorageClass::write(uint8_t b) { _addressData.u8[_writeIndex] = b; _writeIndex++; if (_writeIndex == 4) { _writeIndex = 0; *_writeAddress = _addressData.u32; _writeAddress++; waitForReady(); } return 1; } void InternalStorageClass::close() { while ((int)_writeAddress % PAGE_SIZE) { write(0xff); } } void InternalStorageClass::clear() { } void InternalStorageClass::apply() { // disable interrupts, as vector table will be erase during flash sequence noInterrupts(); copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); } long InternalStorageClass::maxSize() { return MAX_PARTIONED_SKETCH_SIZE; } InternalStorageClass InternalStorage; #endif