diff --git a/boards.txt b/boards.txt index 4d6c41515..c1aad78e6 100644 --- a/boards.txt +++ b/boards.txt @@ -2,7 +2,6 @@ menu.UploadSpeed=Upload Speed menu.CpuFrequency=CPU Frequency menu.FlashSize=Flash Size menu.FlashFreq=Flash Frequency -menu.FlashMode=Flash Mode ############################################################## generic.name=Generic ESP8266 Module @@ -24,6 +23,8 @@ generic.build.flash_mode=qio generic.build.flash_size=512K generic.build.flash_freq=40 generic.build.flash_ld=eagle.flash.512k.ld +generic.build.spiffs_start=0x6B000 +generic.build.spiffs_end=0x7B000 generic.menu.CpuFrequency.80=80 MHz generic.menu.CpuFrequency.80.build.f_cpu=80000000L @@ -49,39 +50,46 @@ generic.menu.UploadSpeed.512000.upload.speed=512000 generic.menu.UploadSpeed.921600=921600 generic.menu.UploadSpeed.921600.upload.speed=921600 -generic.menu.FlashSize.512K=512K +generic.menu.FlashSize.512K=512K (64K SPIFFS) generic.menu.FlashSize.512K.build.flash_size=512K generic.menu.FlashSize.512K.build.flash_ld=eagle.flash.512k.ld -generic.menu.FlashSize.256K=256K -generic.menu.FlashSize.256K.build.flash_size=256K -generic.menu.FlashSize.256K.build.flash_ld=eagle.flash.256k.ld -generic.menu.FlashSize.1M=1M -generic.menu.FlashSize.1M.build.flash_size=1M -generic.menu.FlashSize.1M.build.flash_ld=eagle.flash.1m.ld -generic.menu.FlashSize.2M=2M +generic.menu.FlashSize.512K.build.spiffs_start=0x6B000 +generic.menu.FlashSize.512K.build.spiffs_end=0x7B000 +generic.menu.FlashSize.1M512=1M (512K SPIFFS) +generic.menu.FlashSize.1M512.build.flash_size=1M +generic.menu.FlashSize.1M512.build.flash_ld=eagle.flash.1m512.ld +generic.menu.FlashSize.1M512.build.spiffs_start=0x6B000 +generic.menu.FlashSize.1M512.build.spiffs_end=0xFB000 +generic.menu.FlashSize.1M256=1M (256K SPIFFS) +generic.menu.FlashSize.1M256.build.flash_size=1M +generic.menu.FlashSize.1M256.build.flash_ld=eagle.flash.1m256.ld +generic.menu.FlashSize.1M256.build.spiffs_start=0xAB000 +generic.menu.FlashSize.1M256.build.spiffs_end=0xFB000 +generic.menu.FlashSize.1M128=1M (128K SPIFFS) +generic.menu.FlashSize.1M128.build.flash_size=1M +generic.menu.FlashSize.1M128.build.flash_ld=eagle.flash.1m128.ld +generic.menu.FlashSize.1M128.build.spiffs_start=0xCB000 +generic.menu.FlashSize.1M128.build.spiffs_end=0xFB000 +generic.menu.FlashSize.1M64=1M (64K SPIFFS) +generic.menu.FlashSize.1M64.build.flash_size=1M +generic.menu.FlashSize.1M64.build.flash_ld=eagle.flash.1m64.ld +generic.menu.FlashSize.1M64.build.spiffs_start=0xEB000 +generic.menu.FlashSize.1M64.build.spiffs_end=0xFB000 +generic.menu.FlashSize.2M=2M (1M SPIFFS) generic.menu.FlashSize.2M.build.flash_size=2M generic.menu.FlashSize.2M.build.flash_ld=eagle.flash.2m.ld -generic.menu.FlashSize.4M=4M +generic.menu.FlashSize.2M.build.spiffs_start=0x100000 +generic.menu.FlashSize.2M.build.spiffs_end=0x1FB000 +generic.menu.FlashSize.4M=4M (3M SPIFFS) generic.menu.FlashSize.4M.build.flash_size=4M generic.menu.FlashSize.4M.build.flash_ld=eagle.flash.4m.ld +generic.menu.FlashSize.4M.build.spiffs_start=0x100000 +generic.menu.FlashSize.4M.build.spiffs_end=0x3FB000 -generic.menu.FlashFreq.40=40MHz -generic.menu.FlashFreq.40.build.flash_freq=40 -generic.menu.FlashFreq.20=20MHz -generic.menu.FlashFreq.20.build.flash_freq=20 -generic.menu.FlashFreq.26=26.7MHz -generic.menu.FlashFreq.26.build.flash_freq=26.7 -generic.menu.FlashFreq.80=80MHz -generic.menu.FlashFreq.80.build.flash_freq=80 - -generic.menu.FlashMode.qio=QIO -generic.menu.FlashMode.qio.build.flash_mode=qio -generic.menu.FlashMode.qout=QOUT -generic.menu.FlashMode.qout.build.flash_mode=qout -generic.menu.FlashMode.dio=DIO -generic.menu.FlashMode.dio.build.flash_mode=dio -generic.menu.FlashMode.dout=DOUT -generic.menu.FlashMode.dout.build.flash_mode=dout +# generic.menu.FlashFreq.40=40MHz +# generic.menu.FlashFreq.40.build.flash_freq=40 +# generic.menu.FlashFreq.80=80MHz +# generic.menu.FlashFreq.80.build.flash_freq=80 ############################################################## modwifi.name=Olimex MOD-WIFI-ESP8266(-DEV) @@ -104,6 +112,8 @@ modwifi.build.flash_mode=qio modwifi.build.flash_size=2M modwifi.build.flash_freq=40 modwifi.build.flash_ld=eagle.flash.2m.ld +modwifi.build.spiffs_start=0x100000 +modwifi.build.spiffs_end=0x1FB000 modwifi.menu.CpuFrequency.80=80 MHz modwifi.menu.CpuFrequency.80.build.f_cpu=80000000L @@ -150,6 +160,8 @@ nodemcu.build.flash_mode=qio nodemcu.build.flash_size=4M nodemcu.build.flash_freq=40 nodemcu.build.flash_ld=eagle.flash.4m.ld +nodemcu.build.spiffs_start=0x100000 +nodemcu.build.spiffs_end=0x3FB000 nodemcu.menu.CpuFrequency.80=80 MHz nodemcu.menu.CpuFrequency.80.build.f_cpu=80000000L @@ -176,9 +188,6 @@ nodemcu.menu.UploadSpeed.512000.upload.speed=512000 nodemcu.menu.UploadSpeed.921600=921600 nodemcu.menu.UploadSpeed.921600.upload.speed=921600 -nodemcu.menu.FlashSize.4M=4M -nodemcu.menu.FlashSize.4M.build.flash_size=4M - ############################################################## # wifio.name=Wifio # @@ -197,6 +206,8 @@ nodemcu.menu.FlashSize.4M.build.flash_size=4M # wifio.build.flash_size=512K # wifio.build.flash_freq=40 # wifio.build.flash_ld=eagle.flash.512k.ld +# wifio.build.spiffs_start=0x6B000 +# wifio.build.spiffs_end=0x7B000 # # wifio.menu.CpuFrequency.80=80MHz # wifio.menu.CpuFrequency.80.build.f_cpu=80000000L diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 1170b6f4a..4a2bd7144 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -135,7 +135,7 @@ void ets_intr_unlock(); extern uint32_t interruptsState; #define interrupts() xt_enable_interrupts(interruptsState) -#define noInterrupts() xt_disable_interrupts(interruptsState, 15) +#define noInterrupts() __asm__ __volatile__("rsil %0,15; esync; isync; dsync" : "=a" (interruptsState)) #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) diff --git a/cores/esp8266/FileSystem.cpp b/cores/esp8266/FileSystem.cpp old mode 100755 new mode 100644 index ce722e7ec..735bb7d4a --- a/cores/esp8266/FileSystem.cpp +++ b/cores/esp8266/FileSystem.cpp @@ -22,45 +22,72 @@ #include "Arduino.h" bool FSClass::mount() { - if (_mounted) - return true; - - _mounted = spiffs_mount(); - return _mounted; + if(SPIFFS_mounted(&_filesystemStorageHandle)) return true; + int res = spiffs_mount(); + if(res != 0){ + int formated = SPIFFS_format(&_filesystemStorageHandle); + if(formated != 0) return false; + res = spiffs_mount(); + } + return (res == 0); } void FSClass::unmount() { - if (!_mounted) - return; - - spiffs_unmount(); - _mounted = false; + if(SPIFFS_mounted(&_filesystemStorageHandle)) + SPIFFS_unmount(&_filesystemStorageHandle); } bool FSClass::format() { - return spiffs_format(); + if(!SPIFFS_mounted(&_filesystemStorageHandle)){ + spiffs_mount(); + } + SPIFFS_unmount(&_filesystemStorageHandle); + int formated = SPIFFS_format(&_filesystemStorageHandle); + if(formated != 0) return false; + return (spiffs_mount() == 0); } -bool FSClass::exists(const char *filename) { +bool FSClass::check() { + return SPIFFS_check(&_filesystemStorageHandle) == 0; +} + +bool FSClass::exists(char *filename) { spiffs_stat stat = {0}; if (SPIFFS_stat(&_filesystemStorageHandle, filename, &stat) < 0) return false; return stat.name[0] != '\0'; } -bool FSClass::create(const char *filepath){ +bool FSClass::create(char *filepath){ return SPIFFS_creat(&_filesystemStorageHandle, filepath, 0) == 0; } -bool FSClass::remove(const char *filepath){ +bool FSClass::remove(char *filepath){ return SPIFFS_remove(&_filesystemStorageHandle, filepath) == 0; } -bool FSClass::rename(const char *filename, const char *newname) { +bool FSClass::rename(char *filename, char *newname) { return SPIFFS_rename(&_filesystemStorageHandle, filename, newname) == 0; } -FSFile FSClass::open(const char *filename, uint8_t mode) { +size_t FSClass::totalBytes(){ + u32_t totalBytes; + u32_t usedBytes; + if(SPIFFS_info(&_filesystemStorageHandle, &totalBytes, &usedBytes) == 0) + return totalBytes; + return 0; +} + +size_t FSClass::usedBytes(){ + u32_t totalBytes; + u32_t usedBytes; + if(SPIFFS_info(&_filesystemStorageHandle, &totalBytes, &usedBytes) == 0) + return usedBytes; + return 0; +} + +FSFile FSClass::open(char *filename, uint8_t mode) { + if(String(filename) == "" || String(filename) == "/") return FSFile("/"); int repeats = 0; bool notExist; bool canRecreate = (mode & SPIFFS_CREAT) == SPIFFS_CREAT; @@ -71,7 +98,7 @@ FSFile FSClass::open(const char *filename, uint8_t mode) { res = SPIFFS_open(&_filesystemStorageHandle, filename, (spiffs_flags)mode, 0); int code = SPIFFS_errno(&_filesystemStorageHandle); if (res < 0){ - debugf("open errno %d\n", code); + SPIFFS_API_DBG_E("open errno %d\n", code); notExist = (code == SPIFFS_ERR_NOT_FOUND || code == SPIFFS_ERR_DELETED || code == SPIFFS_ERR_FILE_DELETED || code == SPIFFS_ERR_IS_FREE); if (notExist && canRecreate) remove(filename); // fix for deleted files @@ -84,6 +111,14 @@ FSFile FSClass::open(const char *filename, uint8_t mode) { return FSFile(); } +FSFile FSClass::open(spiffs_dirent* entry, uint8_t mode){ + int res = SPIFFS_open_by_dirent(&_filesystemStorageHandle, entry, (spiffs_flags)mode, 0); + if(res){ + return FSFile(res); + } + return FSFile(); +} + FSClass FS; FSFile::FSFile() { @@ -91,95 +126,140 @@ FSFile::FSFile() { _stats = {0}; } +FSFile::FSFile(String path) { + if(path == "/"){ + _file = 0x1; + os_sprintf((char*)_stats.name, "%s", (char*)path.c_str()); + _stats.size = 0; + _stats.type = SPIFFS_TYPE_DIR; + SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); + } else { + _file = SPIFFS_open(&_filesystemStorageHandle, (char *)path.c_str(), (spiffs_flags)FSFILE_READ, 0); + if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ + SPIFFS_API_DBG_E("fstat errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); + } + //debugf("FSFile name: %s, size: %d, type: %d\n", _stats.name, _stats.size, _stats.type); + if(_stats.type == SPIFFS_TYPE_DIR){ + SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); + } + } +} + FSFile::FSFile(file_t f) { _file = f; if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ - debugf("mount errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); + SPIFFS_API_DBG_E("fstat errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); + } + //debugf("FSFile name: %s, size: %d, type: %d\n", _stats.name, _stats.size, _stats.type); + if(_stats.type == SPIFFS_TYPE_DIR){ + SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); } } void FSFile::close() { if (! _file) return; - SPIFFS_close(&_filesystemStorageHandle, _file); + if(_stats.type == SPIFFS_TYPE_DIR){ + SPIFFS_closedir(&_dir); + } + if(os_strlen((char*)_stats.name) > 1) + SPIFFS_close(&_filesystemStorageHandle, _file); _file = 0; } +char * FSFile::name(){ + return (char*)_stats.name; +} + +bool FSFile::isDirectory(void) { + return _stats.type == SPIFFS_TYPE_DIR; +} + +void FSFile::rewindDirectory() { + if (!_file || !isDirectory()) return; + SPIFFS_closedir(&_dir); + SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); +} + +FSFile FSFile::openNextFile(){ + if (!_file || !isDirectory()) return FSFile(); + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + if ((pe = SPIFFS_readdir(&_dir, pe))){ + return FS.open((char *)pe->name); + } + return FSFile(); +} + uint32_t FSFile::size() { - if(! _file) return 0; + if(!_file) return 0; + if(_stats.size) return _stats.size; uint32_t pos = SPIFFS_tell(&_filesystemStorageHandle, _file); SPIFFS_lseek(&_filesystemStorageHandle, _file, 0, SPIFFS_SEEK_END); - uint32_t size = SPIFFS_tell(&_filesystemStorageHandle, _file); + _stats.size = SPIFFS_tell(&_filesystemStorageHandle, _file); SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); - return size; + return _stats.size; +} + +int FSFile::available() { + if (!_file) return 0; + uint32_t pos = SPIFFS_tell(&_filesystemStorageHandle, _file); + return size() - pos; } uint32_t FSFile::seek(uint32_t pos) { - if (! _file) return 0; + if (!_file) return 0; return SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); } uint32_t FSFile::position() { - if (! _file) return 0; + if (!_file) return 0; return SPIFFS_tell(&_filesystemStorageHandle, _file); } bool FSFile::eof() { - if (! _file) return 0; + if (!_file) return 0; return SPIFFS_eof(&_filesystemStorageHandle, _file); } -bool FSFile::isDirectory(void) { - return false; -} - int FSFile::read(void *buf, uint16_t nbyte) { - if (! _file) return -1; + if (! _file || isDirectory()) return -1; return SPIFFS_read(&_filesystemStorageHandle, _file, buf, nbyte); } int FSFile::read() { - if (! _file) return -1; + if (! _file || isDirectory()) return -1; int val; if(SPIFFS_read(&_filesystemStorageHandle, _file, &val, 1) != 1) return -1; return val; } int FSFile::peek() { - if (! _file) return 0; + if (! _file || isDirectory()) return 0; int c = read(); SPIFFS_lseek(&_filesystemStorageHandle, _file, -1, SPIFFS_SEEK_CUR); return c; } -int FSFile::available() { - if (! _file) return 0; - uint32_t pos = SPIFFS_tell(&_filesystemStorageHandle, _file); - SPIFFS_lseek(&_filesystemStorageHandle, _file, 0, SPIFFS_SEEK_END); - uint32_t size = SPIFFS_tell(&_filesystemStorageHandle, _file); - SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); - return size - pos; -} - size_t FSFile::write(const uint8_t *buf, size_t size){ - if (! _file) return 0; + if (! _file || isDirectory()) return 0; int res = SPIFFS_write(&_filesystemStorageHandle, _file, (uint8_t *)buf, size); return (res > 0)?(size_t)res:0; } size_t FSFile::write(uint8_t val) { - if (! _file) return 0; + if (! _file || isDirectory()) return 0; return write(&val, 1); } void FSFile::flush(){ - if (! _file) return; + if (! _file || isDirectory()) return; SPIFFS_fflush(&_filesystemStorageHandle, _file); } -uint32_t FSFile::remove(){ +bool FSFile::remove(){ if (! _file) return 0; - return SPIFFS_fremove(&_filesystemStorageHandle, _file); - _file = 0; + close(); + return SPIFFS_remove(&_filesystemStorageHandle, (char *)_stats.name) == 0; } int FSFile::lastError(){ @@ -187,28 +267,5 @@ int FSFile::lastError(){ } void FSFile::clearError(){ - _filesystemStorageHandle.errno = SPIFFS_OK; + _filesystemStorageHandle.err_code = SPIFFS_OK; } - -char * FSFile::name(){ - return 0; -} - - - - - - -/* -spiffs_DIR *dirOpen(spiffs_DIR *d){ - return SPIFFS_opendir(&_filesystemStorageHandle, 0, d); -} - -int dirClose(spiffs_DIR *d){ - return SPIFFS_closedir(d); -} - -file_t dirOpenFile(spiffs_dirent* entry, uint8_t flags){ - return SPIFFS_open_by_dirent(&_filesystemStorageHandle, entry, (spiffs_flags)flags, 0); -} -*/ diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h old mode 100755 new mode 100644 index 460595cf3..41659da11 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -26,14 +26,17 @@ class String; #define FSFILE_READ SPIFFS_RDONLY -#define FSFILE_WRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC) +#define FSFILE_WRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND ) +#define FSFILE_OVERWRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC ) class FSFile : public Stream { private: spiffs_stat _stats; file_t _file; + spiffs_DIR _dir; public: + FSFile(String path); FSFile(file_t f); FSFile(void); virtual size_t write(uint8_t); @@ -44,16 +47,18 @@ public: virtual void flush(); int read(void *buf, uint16_t nbyte); uint32_t seek(uint32_t pos); - uint32_t remove(); uint32_t position(); uint32_t size(); bool eof(); void close(); + bool remove(); int lastError(); void clearError(); operator bool() { return _file > 0; } char * name(); bool isDirectory(void); + void rewindDirectory(void); + FSFile openNextFile(void); template size_t write(T &src){ const size_t bufferSize = 64; @@ -80,18 +85,28 @@ public: class FSClass { private: - bool _mounted = false; public: bool mount(); void unmount(); bool format(); - bool exists(const char *filename); - bool create(const char *filepath); - bool remove(const char *filepath); - bool rename(const char *filename, const char *newname); + bool check(); + bool exists(char *filename); + bool create(char *filepath); + bool remove(char *filepath); + bool rename(char *filename, char *newname); + size_t totalBytes(); + size_t usedBytes(); + size_t size(){ return _filesystemStorageHandle.cfg.phys_size; } + size_t blockSize(){ return _filesystemStorageHandle.cfg.log_block_size; } + size_t totalBlocks(){ return _filesystemStorageHandle.block_count; } + size_t freeBlocks(){ return _filesystemStorageHandle.free_blocks; } + size_t pageSize(){ return _filesystemStorageHandle.cfg.log_page_size; } + size_t allocatedPages(){ return _filesystemStorageHandle.stats_p_allocated; } + size_t deletedPages(){ return _filesystemStorageHandle.stats_p_deleted; } - FSFile open(const char *filename, uint8_t mode = FSFILE_READ); + FSFile open(char *filename, uint8_t mode = FSFILE_READ); + FSFile open(spiffs_dirent* entry, uint8_t mode = FSFILE_READ); private: friend class FSFile; diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 87fd6dfbb..ac56919ca 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -42,12 +42,12 @@ extern "C" { #define UART_TX_FIFO_SIZE 0x80 struct uart_ { - int uart_nr; + int uart_nr; int baud_rate; bool rxEnabled; bool txEnabled; - uint8_t rxPin; - uint8_t txPin; + uint8_t rxPin; + uint8_t txPin; }; static const int UART0 = 0; @@ -120,7 +120,7 @@ void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) { // -------------- UART 0 -------------- if(Serial.isRxEnabled()) { while(U0IS & (1 << UIFF)) { - Serial._rx_complete_irq((char)(U0F & 0xff)); + Serial._rx_complete_irq((char) (U0F & 0xff)); U0IC = (1 << UIFF); } } @@ -135,7 +135,7 @@ void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) { if(Serial1.isRxEnabled()) { while(U1IS & (1 << UIFF)) { - Serial1._rx_complete_irq((char)(U1F & 0xff)); + Serial1._rx_complete_irq((char) (U1F & 0xff)); U1IC = (1 << UIFF); } } @@ -357,19 +357,19 @@ void uart_swap(uart_t* uart) { switch(uart->uart_nr) { case UART0: if(uart->txPin == 1 && uart->rxPin == 3) { - pinMode(15, FUNCTION_4);//TX - pinMode(13, FUNCTION_4);//RX + pinMode(15, FUNCTION_4); //TX + pinMode(13, FUNCTION_4); //RX USWAP |= (1 << USWAP0); - pinMode(1, INPUT);//TX - pinMode(3, INPUT);//RX + pinMode(1, INPUT); //TX + pinMode(3, INPUT); //RX uart->rxPin = 13; uart->txPin = 15; } else { - pinMode(1, SPECIAL);//TX - pinMode(3, SPECIAL);//RX + pinMode(1, SPECIAL); //TX + pinMode(3, SPECIAL); //RX USWAP &= ~(1 << USWAP0); - pinMode(15, INPUT);//TX - pinMode(13, INPUT);//RX + pinMode(15, INPUT); //TX + pinMode(13, INPUT); //RX uart->rxPin = 3; uart->txPin = 1; } @@ -392,30 +392,50 @@ void uart_ignore_char(char c) { void uart0_write_char(char c) { if(&Serial != NULL && Serial.isTxEnabled()) { - if(c == '\n') { - Serial.write('\r'); + if(Serial.availableForWrite() > 0) { + if(c == '\n') { + Serial.write('\r'); + } + Serial.write(c); + return; } - Serial.write(c); - } else { - if(c == '\n') { - USF(0) = '\r'; - } - USF(0) = c; } + + // wait for the Hardware FIFO + while(true) { + if(((USS(0) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { + break; + } + } + + if(c == '\n') { + USF(0) = '\r'; + } + USF(0) = c; } void uart1_write_char(char c) { if(&Serial1 != NULL && Serial1.isTxEnabled()) { - if(c == '\n') { - Serial1.write('\r'); + if(Serial1.availableForWrite() > 0) { + if(c == '\n') { + Serial1.write('\r'); + } + Serial1.write(c); + return; } - Serial1.write(c); - } else { - if(c == '\n') { - USF(1) = '\r'; - } - USF(1) = c; } + + // wait for the Hardware FIFO + while(true) { + if(((USS(1) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { + break; + } + } + + if(c == '\n') { + USF(1) = '\r'; + } + USF(1) = c; } static int s_uart_debug_nr = UART0; @@ -465,11 +485,11 @@ void HardwareSerial::begin(unsigned long baud, byte config) { } if(_uart->rxEnabled) { - if (!_rx_buffer) + if(!_rx_buffer) _rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE); } if(_uart->txEnabled) { - if (!_tx_buffer) + if(!_tx_buffer) _tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE); } _written = false; diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index c1405c9f7..1f924248a 100644 --- a/cores/esp8266/Print.cpp +++ b/cores/esp8266/Print.cpp @@ -30,6 +30,7 @@ #include "Print.h" extern "C" { #include "c_types.h" +#include "ets_sys.h" } // Public Methods ////////////////////////////////////////////////////////////// @@ -43,6 +44,16 @@ size_t ICACHE_FLASH_ATTR Print::write(const uint8_t *buffer, size_t size) { return n; } +size_t Print::printf(const char *format, ...) { + va_list arg; + va_start(arg, format); + char temp[256]; + size_t len = ets_vsnprintf(temp, 256, format, arg); + len = print(temp); + va_end(arg); + return len; +} + size_t ICACHE_FLASH_ATTR Print::print(const __FlashStringHelper *ifsh) { PGM_P p = reinterpret_cast(ifsh); diff --git a/cores/esp8266/Print.h b/cores/esp8266/Print.h index 79358f157..7366174f5 100644 --- a/cores/esp8266/Print.h +++ b/cores/esp8266/Print.h @@ -63,6 +63,7 @@ class Print { return write((const uint8_t *) buffer, size); } + size_t printf(const char * format, ...); size_t print(const __FlashStringHelper *); size_t print(const String &); size_t print(const char[]); diff --git a/cores/esp8266/abi.cpp b/cores/esp8266/abi.cpp index add40bcb1..b863997a3 100644 --- a/cores/esp8266/abi.cpp +++ b/cores/esp8266/abi.cpp @@ -26,10 +26,12 @@ extern "C" { } void *operator new(size_t size) { + size = ((size + 3) & ~((size_t)0x3)); return os_malloc(size); } void *operator new[](size_t size) { + size = ((size + 3) & ~((size_t)0x3)); return os_malloc(size); } diff --git a/cores/esp8266/core_esp8266_noniso.c b/cores/esp8266/core_esp8266_noniso.c index a7efef4c4..eafe4fa72 100644 --- a/cores/esp8266/core_esp8266_noniso.c +++ b/cores/esp8266/core_esp8266_noniso.c @@ -188,10 +188,10 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) { ++out; } - while(prec-- > 0) { + for (unsigned char decShift = prec; decShift > 0; decShift--) { remainder *= 10.0; } - sprintf(out, "%d", (int) remainder); + sprintf(out, "%0*d", prec, (int)remainder); return s; } diff --git a/cores/esp8266/libc_replacements.c b/cores/esp8266/libc_replacements.c index 64efd94ab..519ea233a 100644 --- a/cores/esp8266/libc_replacements.c +++ b/cores/esp8266/libc_replacements.c @@ -38,6 +38,7 @@ #include "user_interface.h" void* malloc(size_t size) { + size = ((size + 3) & ~((size_t)0x3)); return os_malloc(size); } @@ -46,6 +47,7 @@ void free(void* ptr) { } void* realloc(void* ptr, size_t size) { + size = ((size + 3) & ~((size_t)0x3)); return os_realloc(ptr, size); } diff --git a/cores/esp8266/spiffs/docs/INTEGRATION b/cores/esp8266/spiffs/INTEGRATION old mode 100755 new mode 100644 similarity index 99% rename from cores/esp8266/spiffs/docs/INTEGRATION rename to cores/esp8266/spiffs/INTEGRATION index 085ed8fc1..20ff70d05 --- a/cores/esp8266/spiffs/docs/INTEGRATION +++ b/cores/esp8266/spiffs/INTEGRATION @@ -303,4 +303,4 @@ Having these figures you can disable SPIFFS_BUFFER_HELP again to save flash. * HOW TO CONFIG -TODO \ No newline at end of file +TODO diff --git a/cores/esp8266/spiffs/Makefile b/cores/esp8266/spiffs/Makefile deleted file mode 100755 index 1c44e4ace..000000000 --- a/cores/esp8266/spiffs/Makefile +++ /dev/null @@ -1,44 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR -GEN_LIBS = spiffs.a -endif - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -INCLUDES += -I ./ -INCLUDES += -I ../libc -INCLUDES += -I ../platform -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile diff --git a/cores/esp8266/spiffs/README b/cores/esp8266/spiffs/README new file mode 100644 index 000000000..6efd656cb --- /dev/null +++ b/cores/esp8266/spiffs/README @@ -0,0 +1,86 @@ +SPIFFS (SPI Flash File System) +V0.3.0 + +Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976gmail.com) + +For legal stuff, see LICENCE in this directory. Basically, you may do whatever +you want with the source. Use, modify, sell, print it out, roll it and smoke it + - as long as I won't be held responsible. + +Love to hear feedback though! + + +* INTRODUCTION + +Spiffs is a file system intended for SPI NOR flash devices on embedded targets. + +Spiffs is designed with following characteristics in mind: + - Small (embedded) targets, sparse RAM without heap + - Only big areas of data (blocks) can be erased + - An erase will reset all bits in block to ones + - Writing pulls one to zeroes + - Zeroes can only be pulled to ones by erase + - Wear leveling + + +* FEATURES + +What spiffs does: + - Specifically designed for low ram usage + - Uses statically sized ram buffers, independent of number of files + - Posix-like api: open, close, read, write, seek, stat, etc + - It can be run on any NOR flash, not only SPI flash - theoretically also on + embedded flash of an microprocessor + - Multiple spiffs configurations can be run on same target - and even on same + SPI flash device + - Implements static wear leveling + - Built in file system consistency checks + +What spiffs does not: + - Presently, spiffs does not support directories. It produces a flat + structure. Creating a file with path "tmp/myfile.txt" will create a file + called "tmp/myfile.txt" instead of a "myfile.txt" under directory "tmp". + - It is not a realtime stack. One write operation might take much longer than + another. + - Poor scalability. Spiffs is intended for small memory devices - the normal + sizes for SPI flashes. Going beyond ~128MB is probably a bad idea. This is + a side effect of the design goal to use as little ram as possible. + - Presently, it does not detect or handle bad blocks. + + +* MORE INFO + +For integration, see the docs/INTEGRATION file. + +For use and design, see the docs/TECH_SPEC file. + +For testing and contributions, see the docs/IMPLEMENTING file. + +* HISTORY + +0.3.0 + Added existing namecheck when creating files + Lots of static analysis bugs #6 + Added rename func + Fix SPIFFS_read length when reading beyond file size + Added reading beyond file length testcase + Made build a bit more configurable + Changed name in spiffs from "errno" to "err_code" due to conflicts compiling + in mingw + Improved GC checks, fixed an append bug, more robust truncate for very special + case + GC checks preempts GC, truncate even less picky + Struct alignment needed for some targets, define in spiffs config #10 + Spiffs filesystem magic, definable in config + + New config defines: + SPIFFS_USE_MAGIC - enable or disable magic check upon mount + SPIFFS_ALIGNED_OBJECT_INDEX_TABLES - alignment for certain targets + New API functions: + SPIFFS_rename - rename files + SPIFFS_clearerr - clears last errno + SPIFFS_info - returns info on used and total bytes in fs + SPIFFS_format - formats the filesystem + SPIFFS_mounted - checks if filesystem is mounted + + diff --git a/cores/esp8266/spiffs/docs/TECH_SPEC b/cores/esp8266/spiffs/TECH_SPEC old mode 100755 new mode 100644 similarity index 100% rename from cores/esp8266/spiffs/docs/TECH_SPEC rename to cores/esp8266/spiffs/TECH_SPEC diff --git a/cores/esp8266/spiffs/TODO b/cores/esp8266/spiffs/TODO new file mode 100644 index 000000000..c947316a8 --- /dev/null +++ b/cores/esp8266/spiffs/TODO @@ -0,0 +1,15 @@ +* When mending lost pages, also see if they fit into length specified in object index header + +SPIFFS2 thoughts + +* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id. + Eg. object id xor:ed with bit-reversed span index. + This should decrease number of actual pages that needs to be visited when looking thru the obj lut. + +* Logical number of each block. When moving stuff in a garbage collected page, the free + page is assigned the same number as the garbage collected. Thus, object index pages do not have to + be rewritten. + +* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit + as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a + check is automatically run. \ No newline at end of file diff --git a/cores/esp8266/spiffs/docs/IMPLEMENTING b/cores/esp8266/spiffs/docs/IMPLEMENTING deleted file mode 100755 index e69de29bb..000000000 diff --git a/cores/esp8266/spiffs/docs/TODO b/cores/esp8266/spiffs/docs/TODO deleted file mode 100755 index 88709f022..000000000 --- a/cores/esp8266/spiffs/docs/TODO +++ /dev/null @@ -1 +0,0 @@ -* When mending lost pages, also see if they fit into length specified in object index header \ No newline at end of file diff --git a/cores/esp8266/spiffs/flashmem.h b/cores/esp8266/spiffs/flashmem.h deleted file mode 100755 index c4f4252a1..000000000 --- a/cores/esp8266/spiffs/flashmem.h +++ /dev/null @@ -1,73 +0,0 @@ -// Based on NodeMCU platform_flash -// https://github.com/nodemcu/nodemcu-firmware - -#ifndef SYSTEM_FLASHMEM_H_ -#define SYSTEM_FLASHMEM_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "spiffs.h" -#include "spi_flash.h" - -#define INTERNAL_FLASH_WRITE_UNIT_SIZE 4 -#define INTERNAL_FLASH_READ_UNIT_SIZE 4 - -#define FLASH_TOTAL_SEC_COUNT (flashmem_get_size_sectors()) - -#define SYS_PARAM_SEC_COUNT 4 -#define FLASH_WORK_SEC_COUNT (FLASH_TOTAL_SEC_COUNT - SYS_PARAM_SEC_COUNT) - -#define INTERNAL_FLASH_SECTOR_SIZE SPI_FLASH_SEC_SIZE -#define INTERNAL_FLASH_SIZE ( (FLASH_WORK_SEC_COUNT) * INTERNAL_FLASH_SECTOR_SIZE ) -#define INTERNAL_FLASH_START_ADDRESS 0x40200000 - -typedef struct -{ - uint8_t unknown0; - uint8_t unknown1; - enum - { - MODE_QIO = 0, - MODE_QOUT = 1, - MODE_DIO = 2, - MODE_DOUT = 15, - } mode : 8; - enum - { - SPEED_40MHZ = 0, - SPEED_26MHZ = 1, - SPEED_20MHZ = 2, - SPEED_80MHZ = 15, - } speed : 4; - enum - { - SIZE_4MBIT = 0, - SIZE_2MBIT = 1, - SIZE_8MBIT = 2, - SIZE_16MBIT = 3, - SIZE_32MBIT = 4, - } size : 4; -} STORE_TYPEDEF_ATTR SPIFlashInfo; - -extern uint32_t flashmem_write( const void *from, uint32_t toaddr, uint32_t size ); -extern uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ); -extern bool flashmem_erase_sector( uint32_t sector_id ); - -extern SPIFlashInfo flashmem_get_info(); -extern uint8_t flashmem_get_size_type(); -extern uint32_t flashmem_get_size_bytes(); -extern uint16_t flashmem_get_size_sectors(); -uint32_t flashmem_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend ); -uint32_t flashmem_get_sector_of_address( uint32_t addr ); - -extern uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t size ); -extern uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ); -extern uint32_t flashmem_get_first_free_block_address(); - -#ifdef __cplusplus -} -#endif - -#endif /* SYSTEM_FLASHMEM_H_ */ diff --git a/cores/esp8266/spiffs/spiffs.c b/cores/esp8266/spiffs/spiffs.c deleted file mode 100755 index c07be839a..000000000 --- a/cores/esp8266/spiffs/spiffs.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "spiffs.h" - -#define LOG_PAGE_SIZE 256 - -spiffs _filesystemStorageHandle; - -static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2]; -static u8_t spiffs_fds[32*4]; -static u8_t spiffs_cache[(LOG_PAGE_SIZE+32)*4]; - -static s32_t api_spiffs_read(u32_t addr, u32_t size, u8_t *dst){ - flashmem_read(dst, addr, size); - return SPIFFS_OK; -} - -static s32_t api_spiffs_write(u32_t addr, u32_t size, u8_t *src){ - flashmem_write(src, addr, size); - return SPIFFS_OK; -} - -static s32_t api_spiffs_erase(u32_t addr, u32_t size){ - debugf("api_spiffs_erase"); - u32_t sect_first = flashmem_get_sector_of_address(addr); - u32_t sect_last = sect_first; - while( sect_first <= sect_last ) - if( !flashmem_erase_sector( sect_first ++ ) ) - return SPIFFS_ERR_INTERNAL; - return SPIFFS_OK; -} - -/******************* -The W25Q32BV array is organized into 16,384 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time. -Pages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or -the entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 64 erasable blocks respectively. -The small 4KB sectors allow for greater flexibility in applications that require data and parameter storage. -********************/ - -extern uint32_t _SPIFFS_start; -extern uint32_t _SPIFFS_end; - -spiffs_config spiffs_get_storage_config() -{ - spiffs_config cfg = {0}; - if ((u32_t)&_SPIFFS_start == 0) return cfg; - cfg.phys_addr = (u32_t)&_SPIFFS_start; - cfg.phys_size = (u32_t)((u32_t)&_SPIFFS_end - (u32_t)&_SPIFFS_start); - cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet - cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE * 2; // Important to make large - cfg.log_page_size = LOG_PAGE_SIZE; // as we said - return cfg; -} - -bool spiffs_format_internal(){ - spiffs_config cfg = spiffs_get_storage_config(); - if (cfg.phys_addr == 0){ - SYSTEM_ERROR("Can't format file system, wrong address"); - return false; - } - - u32_t sect_first, sect_last; - sect_first = flashmem_get_first_free_block_address(); - sect_last = flashmem_get_sector_of_address((u32_t)&_SPIFFS_end); - debugf("sect_first: %x, sect_last: %x\n", sect_first, sect_last); - while( sect_first <= sect_last ){ - if(!flashmem_erase_sector( sect_first ++ )) - return false; - } - return true; -} - -bool spiffs_mount(){ - spiffs_config cfg = spiffs_get_storage_config(); - if (cfg.phys_addr == 0){ - SYSTEM_ERROR("Can't start file system, wrong address"); - return false; - } - - debugf("fs.start:%x, size:%d Kb\n", cfg.phys_addr, cfg.phys_size / 1024); - - cfg.hal_read_f = api_spiffs_read; - cfg.hal_write_f = api_spiffs_write; - cfg.hal_erase_f = api_spiffs_erase; - - uint32_t dat; - bool writeFirst = false; - flashmem_read(&dat, cfg.phys_addr, 4); - - if (dat == UINT32_MAX){ - debugf("First init file system"); - if(!spiffs_format_internal()){ - SYSTEM_ERROR("Can't format file system"); - return false; - } - writeFirst = true; - } - - int res = SPIFFS_mount(&_filesystemStorageHandle, - &cfg, - spiffs_work_buf, - spiffs_fds, - sizeof(spiffs_fds), - spiffs_cache, - sizeof(spiffs_cache), - NULL); - debugf("mount res: %d\n", res); - - if(res != 0) return false; - - if (writeFirst){ - file_t fd = SPIFFS_open(&_filesystemStorageHandle, "initialize_fs_header.dat", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); - SPIFFS_write(&_filesystemStorageHandle, fd, (u8_t *)"1", 1); - SPIFFS_fremove(&_filesystemStorageHandle, fd); - SPIFFS_close(&_filesystemStorageHandle, fd); - } - return true; -} - -void spiffs_unmount(){ - SPIFFS_unmount(&_filesystemStorageHandle); -} - -bool spiffs_format(){ - spiffs_unmount(); - if(!spiffs_format_internal()) return false; - spiffs_mount(); - return true; -} - -void test_spiffs(){ - char buf[12] = {0}; - spiffs_file fd; - spiffs_stat st = {0}; - SPIFFS_stat(&_filesystemStorageHandle, "my_file.txt", &st); - if (st.size <= 0){ - fd = SPIFFS_open(&_filesystemStorageHandle, "my_file.txt", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); - if (SPIFFS_write(&_filesystemStorageHandle, fd, (u8_t *)"Hello world", 11) < 0) - debugf("errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); - SPIFFS_close(&_filesystemStorageHandle, fd); - debugf("file created"); - } else debugf("file %s exist :)", st.name); - - fd = SPIFFS_open(&_filesystemStorageHandle, "my_file.txt", SPIFFS_RDWR, 0); - if (SPIFFS_read(&_filesystemStorageHandle, fd, (u8_t *)buf, 11) < 0) debugf("errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); - SPIFFS_close(&_filesystemStorageHandle, fd); - debugf("--> %s <--\n", buf); -} diff --git a/cores/esp8266/spiffs/spiffs.h b/cores/esp8266/spiffs/spiffs.h old mode 100755 new mode 100644 index 6357b44a7..7df7ae049 --- a/cores/esp8266/spiffs/spiffs.h +++ b/cores/esp8266/spiffs/spiffs.h @@ -5,15 +5,15 @@ * Author: petera */ + + #ifndef SPIFFS_H_ #define SPIFFS_H_ - #ifdef __cplusplus extern "C" { #endif #include "spiffs_config.h" -#include "flashmem.h" #define SPIFFS_OK 0 #define SPIFFS_ERR_NOT_MOUNTED -10000 @@ -40,6 +40,13 @@ extern "C" { #define SPIFFS_ERR_NOT_WRITABLE -10021 #define SPIFFS_ERR_NOT_READABLE -10022 #define SPIFFS_ERR_CONFLICTING_NAME -10023 +#define SPIFFS_ERR_NOT_CONFIGURED -10024 + +#define SPIFFS_ERR_NOT_A_FS -10025 +#define SPIFFS_ERR_MOUNTED -10026 +#define SPIFFS_ERR_ERASE_FAIL -10027 +#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028 + #define SPIFFS_ERR_INTERNAL -10050 @@ -81,19 +88,21 @@ typedef enum { } spiffs_check_report; /* file system check callback function */ -typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report, u32_t arg1, u32_t arg2); +typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2); #ifndef SPIFFS_DBG -#define SPIFFS_DBG(...) printf(__VA_ARGS__) +#define SPIFFS_DBG(...) \ + print(__VA_ARGS__) #endif #ifndef SPIFFS_GC_DBG -#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__) +#define SPIFFS_GC_DBG(...) c_printf(__VA_ARGS__) #endif #ifndef SPIFFS_CACHE_DBG -#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__) +#define SPIFFS_CACHE_DBG(...) c_printf(__VA_ARGS__) #endif #ifndef SPIFFS_CHECK_DBG -#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__) +#define SPIFFS_CHECK_DBG(...) c_printf(__VA_ARGS__) #endif /* Any write to the filehandle is appended to end of the file */ @@ -182,7 +191,7 @@ typedef struct { u32_t fd_count; // last error - s32_t errno; + s32_t err_code; // current number of free blocks u32_t free_blocks; @@ -212,6 +221,11 @@ typedef struct { // check callback function spiffs_check_callback check_cb_f; + + // mounted flag + u8_t mounted; + // config magic + u32_t config_magic; } spiffs; /* spiffs file status struct */ @@ -239,7 +253,10 @@ typedef struct { // functions /** - * Initializes the file system dynamic parameters and mounts the filesystem + * Initializes the file system dynamic parameters and mounts the filesystem. + * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS + * if the flash does not contain a recognizable file system. + * In this case, SPIFFS_format must be called prior to remounting. * @param fs the file system struct * @param config the physical and logical configuration of the file system * @param work a memory work buffer comprising 2*config->log_page_size @@ -268,7 +285,7 @@ void SPIFFS_unmount(spiffs *fs); * @param path the path of the new file * @param mode ignored, for posix compliance */ -s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode); +s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode); /** * Opens/creates a file. @@ -279,7 +296,8 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode); * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT * @param mode ignored, for posix compliance */ -spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode); +spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode); + /** * Opens a file by given dir entry. @@ -304,7 +322,7 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl * @param len how much to read * @returns number of bytes read, or -1 if error */ -s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len); +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len); /** * Writes to given filehandle. @@ -314,7 +332,7 @@ s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len); * @param len how much to write * @returns number of bytes written, or -1 if error */ -s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len); +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len); /** * Moves the read/write file offset @@ -332,7 +350,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence); * @param fs the file system struct * @param path the path of the file to remove */ -s32_t SPIFFS_remove(spiffs *fs, const char *path); +s32_t SPIFFS_remove(spiffs *fs, char *path); /** * Removes a file by filehandle @@ -347,7 +365,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh); * @param path the path of the file to stat * @param s the stat struct to populate */ -s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s); +s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s); /** * Gets file status by filehandle @@ -375,9 +393,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh); * Renames a file * @param fs the file system struct * @param old path of file to rename - * @param new new path of file + * @param newPath new path of file */ -s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname); +s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath); /** * Returns last error of last file operation. @@ -385,6 +403,12 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname); */ s32_t SPIFFS_errno(spiffs *fs); +/** + * Clears last error. + * @param fs the file system struct + */ +void SPIFFS_clearerr(spiffs *fs); + /** * Opens a directory stream corresponding to the given name. * The stream is positioned at the first entry in the directory. @@ -394,7 +418,7 @@ s32_t SPIFFS_errno(spiffs *fs); * @param name the name of the directory * @param d pointer the directory stream to be populated */ -spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d); +spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d); /** * Closes a directory stream @@ -416,12 +440,51 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); */ s32_t SPIFFS_check(spiffs *fs); + +/** + * Returns number of total bytes available and number of used bytes. + * This is an estimation, and depends on if there a many files with little + * data or few files with much data. + * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should + * run. This indicates a power loss in midst of things. In worst case + * (repeated powerlosses in mending or gc) you might have to delete some files. + * + * @param fs the file system struct + * @param total total number of bytes in filesystem + * @param used used number of bytes in filesystem + */ +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); + +/** + * Formats the entire file system. All data will be lost. + * The filesystem must not be mounted when calling this. + * + * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount + * MUST be called prior to formatting in order to configure the filesystem. + * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling + * SPIFFS_format. + * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling + * SPIFFS_unmount first. + */ +s32_t SPIFFS_format(spiffs *fs); + +/** + * Returns nonzero if spiffs is mounted, or zero if unmounted. + */ +u8_t SPIFFS_mounted(spiffs *fs); + /** * Check if EOF reached. * @param fs the file system struct * @param fh the filehandle of the file to check */ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh); + +/** + * Get the current position of the data pointer. + * @param fs the file system struct + * @param fh the filehandle of the open file + */ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh); #if SPIFFS_TEST_VISUALISATION @@ -448,19 +511,10 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages); #endif #endif -#if SPIFFS_CACHE -#endif - - -bool spiffs_mount(); -void spiffs_unmount(); -bool spiffs_format(); -spiffs_config spiffs_get_storage_config(); -extern void test_spiffs(); - -extern spiffs _filesystemStorageHandle; +#include "spiffs_esp8266.h" #ifdef __cplusplus } #endif + #endif /* SPIFFS_H_ */ diff --git a/cores/esp8266/spiffs/spiffs_cache.c b/cores/esp8266/spiffs/spiffs_cache.c old mode 100755 new mode 100644 diff --git a/cores/esp8266/spiffs/spiffs_check.c b/cores/esp8266/spiffs/spiffs_check.c old mode 100755 new mode 100644 index aad355122..50bbb5c89 --- a/cores/esp8266/spiffs/spiffs_check.c +++ b/cores/esp8266/spiffs/spiffs_check.c @@ -597,7 +597,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { data_spix_offset + i, data_pix, cur_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("PA: FIXUP: index bad %u, cannot mend - delete object\n", res); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad %d, cannot mend - delete object\n", res); if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0); // delete file res = spiffs_page_delete(fs, cur_pix); @@ -763,7 +763,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("PA: FIXUP: index bad %u, cannot mend!\n", res); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad %d, cannot mend!\n", res); if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); res = spiffs_page_delete(fs, cur_pix); SPIFFS_CHECK_RES(res); diff --git a/cores/esp8266/spiffs/spiffs_config.h b/cores/esp8266/spiffs/spiffs_config.h old mode 100755 new mode 100644 index 095bef900..d59ac80b1 --- a/cores/esp8266/spiffs/spiffs_config.h +++ b/cores/esp8266/spiffs/spiffs_config.h @@ -8,24 +8,11 @@ #ifndef SPIFFS_CONFIG_H_ #define SPIFFS_CONFIG_H_ -// ----------- 8< ------------ -// Following includes are for the linux test build of spiffs -// These may/should/must be removed/altered/replaced in your target -// #include "params_test.h" -//#include "c_stdio.h" -//#include "c_stdlib.h" -//#include "c_string.h" #include "mem.h" #include "c_types.h" #include "stddef.h" #include "osapi.h" #include "ets_sys.h" -// ----------- >8 ------------ -#define IRAM_ATTR __attribute__((section(".iram.text"))) -#define STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) -#define STORE_ATTR __attribute__((aligned(4))) - -#define SPIFFS_CHACHE 0 #define c_memcpy os_memcpy #define c_printf os_printf @@ -56,24 +43,22 @@ typedef uint8_t u8_t; #endif // compile time switches -#define debugf(fmt, ...) //os_printf(fmt"\r\n", ##__VA_ARGS__) -#define SYSTEM_ERROR(fmt, ...) //os_printf("ERROR: " fmt "\r\n", ##__VA_ARGS__) // Set generic spiffs debug output call. #ifndef SPIFFS_DGB -#define SPIFFS_DBG(...) //os_printf(__VA_ARGS__) +#define SPIFFS_DBG(...) //c_printf(__VA_ARGS__) #endif // Set spiffs debug output call for garbage collecting. #ifndef SPIFFS_GC_DGB -#define SPIFFS_GC_DBG(...) //os_printf(__VA_ARGS__) +#define SPIFFS_GC_DBG(...) //c_printf(__VA_ARGS__) #endif // Set spiffs debug output call for caching. #ifndef SPIFFS_CACHE_DGB -#define SPIFFS_CACHE_DBG(...) //os_printf(__VA_ARGS__) +#define SPIFFS_CACHE_DBG(...) //c_printf(__VA_ARGS__) #endif // Set spiffs debug output call for system consistency checks. #ifndef SPIFFS_CHECK_DGB -#define SPIFFS_CHECK_DBG(...) //os_printf(__VA_ARGS__) +#define SPIFFS_CHECK_DBG(...) //c_printf(__VA_ARGS__) #endif // Enable/disable API functions to determine exact number of bytes @@ -108,7 +93,7 @@ typedef uint8_t u8_t; // Define maximum number of gc runs to perform to reach desired free pages. #ifndef SPIFFS_GC_MAX_RUNS -#define SPIFFS_GC_MAX_RUNS 3 +#define SPIFFS_GC_MAX_RUNS 5 #endif // Enable/disable statistics on gc. Debug/test purpose only. @@ -150,14 +135,22 @@ typedef uint8_t u8_t; #define SPIFFS_COPY_BUFFER_STACK (64) #endif +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + // SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level // These should be defined on a multithreaded system -// define this to entering a mutex if you're running on a multithreaded system +// define this to enter a mutex if you're running on a multithreaded system #ifndef SPIFFS_LOCK #define SPIFFS_LOCK(fs) #endif -// define this to exiting a mutex if you're running on a multithreaded system +// define this to exit a mutex if you're running on a multithreaded system #ifndef SPIFFS_UNLOCK #define SPIFFS_UNLOCK(fs) #endif @@ -190,7 +183,12 @@ typedef uint8_t u8_t; #endif #endif -// Set SPFIFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function // in the api. This function will visualize all filesystem using given printf // function. #ifndef SPIFFS_TEST_VISUALISATION diff --git a/cores/esp8266/spiffs/spiffs_esp8266.c b/cores/esp8266/spiffs/spiffs_esp8266.c new file mode 100644 index 000000000..56cf3813c --- /dev/null +++ b/cores/esp8266/spiffs/spiffs_esp8266.c @@ -0,0 +1,224 @@ +#include "spiffs_esp8266.h" +#include "spi_flash.h" +#include "esp8266_peri.h" +#include "Arduino.h" + +/* + FLASH ACCESS FUNCTIONS +*/ + +//lowest level sector erase method +bool flashmem_erase_sector( uint32_t sector_id ){ + WDT_RESET(); + noInterrupts(); + bool erased = spi_flash_erase_sector( sector_id ) == SPI_FLASH_RESULT_OK; + interrupts(); + return erased; +} + +//lowest level data write method +uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t size ){ + toaddr -= INTERNAL_FLASH_START_ADDRESS; + SpiFlashOpResult r; + const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1; + uint32_t *apbuf = NULL; + if(((uint32_t)from) & blkmask){ + apbuf = (uint32_t *)os_malloc(size); + if(!apbuf) + return 0; + os_memcpy(apbuf, from, size); + } + WDT_RESET(); + noInterrupts(); + r = spi_flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); + interrupts(); + if(apbuf) + os_free(apbuf); + if(SPI_FLASH_RESULT_OK == r) + return size; + else{ + SPIFFS_API_DBG_E( "ERROR in flash_write: r=%d at %08X\n", ( int )r, ( unsigned )toaddr+INTERNAL_FLASH_START_ADDRESS ); + return 0; + } +} + +//lowest level data read method +uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ){ + fromaddr -= INTERNAL_FLASH_START_ADDRESS; + SpiFlashOpResult r; + WDT_RESET(); + noInterrupts(); + r = spi_flash_read(fromaddr, (uint32 *)to, size); + interrupts(); + if(SPI_FLASH_RESULT_OK == r) + return size; + else{ + SPIFFS_API_DBG_E( "ERROR in flash_read: r=%d at %08X\n", ( int )r, ( unsigned )fromaddr+INTERNAL_FLASH_START_ADDRESS ); + return 0; + } +} + +//mid level data write method +uint32_t flashmem_write( const void *from, uint32_t toaddr, uint32_t size ){ + uint32_t temp, rest, ssize = size; + unsigned i; + char tmpdata[ INTERNAL_FLASH_WRITE_UNIT_SIZE ]; + const uint8_t *pfrom = ( const uint8_t* )from; + const uint32_t blksize = INTERNAL_FLASH_WRITE_UNIT_SIZE; + const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1; + + // Align the start + if(toaddr & blkmask){ + rest = toaddr & blkmask; + temp = toaddr & ~blkmask; // this is the actual aligned address + // c_memcpy( tmpdata, ( const void* )temp, blksize ); + flashmem_read_internal( tmpdata, temp, blksize ); + for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ ) + tmpdata[ i ] = *pfrom; + flashmem_write_internal( tmpdata, temp, blksize ); + if( size == 0 ) + return ssize; + toaddr = temp + blksize; + } + // The start address is now a multiple of blksize + // Compute how many bytes we can write as multiples of blksize + rest = size & blkmask; + temp = size & ~blkmask; + // Program the blocks now + if(temp){ + flashmem_write_internal( pfrom, toaddr, temp ); + toaddr += temp; + pfrom += temp; + } + // And the final part of a block if needed + if(rest){ + // c_memcpy( tmpdata, ( const void* )toaddr, blksize ); + flashmem_read_internal( tmpdata, toaddr, blksize ); + for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ ) + tmpdata[ i ] = *pfrom; + flashmem_write_internal( tmpdata, toaddr, blksize ); + } + return ssize; +} + +//mid level data write method +uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ){ + uint32_t temp, rest, ssize = size; + unsigned i; + char tmpdata[ INTERNAL_FLASH_READ_UNIT_SIZE ]; + uint8_t *pto = ( uint8_t* )to; + const uint32_t blksize = INTERNAL_FLASH_READ_UNIT_SIZE; + const uint32_t blkmask = INTERNAL_FLASH_READ_UNIT_SIZE - 1; + + // Align the start + if(fromaddr & blkmask){ + rest = fromaddr & blkmask; + temp = fromaddr & ~blkmask; // this is the actual aligned address + flashmem_read_internal( tmpdata, temp, blksize ); + for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ ) + *pto = tmpdata[ i ]; + + if( size == 0 ) + return ssize; + fromaddr = temp + blksize; + } + // The start address is now a multiple of blksize + // Compute how many bytes we can read as multiples of blksize + rest = size & blkmask; + temp = size & ~blkmask; + // Program the blocks now + if(temp){ + flashmem_read_internal( pto, fromaddr, temp ); + fromaddr += temp; + pto += temp; + } + // And the final part of a block if needed + if(rest){ + flashmem_read_internal( tmpdata, fromaddr, blksize ); + for( i = 0; size && ( i < rest ); i ++, size --, pto ++ ) + *pto = tmpdata[ i ]; + } + return ssize; +} + +//shorthand when start and end addresses of the sector are not needed +uint32_t flashmem_get_sector_of_address( uint32_t addr ){ + return (addr - INTERNAL_FLASH_START_ADDRESS) / INTERNAL_FLASH_SECTOR_SIZE;; +} + +/* + SPIFFS BOOTSTRAP +*/ + +//SPIFFS Address Range (defined in eagle ld) +extern uint32_t _SPIFFS_start; +extern uint32_t _SPIFFS_end; + +//SPIFFS Storage Handle +spiffs _filesystemStorageHandle; + +//SPIFFS Buffers (INTERNAL_FLASH_PAGE_SIZE = 256) Total 1792 bytes +static u8_t spiffs_work_buf[INTERNAL_FLASH_PAGE_SIZE*2]; //512 bytes +static u8_t spiffs_fds[32*4]; //128 bytes +static u8_t spiffs_cache[(INTERNAL_FLASH_PAGE_SIZE+32)*4]; //1152 bytes + +//SPIFFS API Read CallBack +static s32_t api_spiffs_read(u32_t addr, u32_t size, u8_t *dst){ + SPIFFS_API_DBG_V("api_spiffs_read: 0x%08x len: %u\n", addr, size); + flashmem_read(dst, addr, size); + return SPIFFS_OK; +} + +//SPIFFS API Write CallBack +static s32_t api_spiffs_write(u32_t addr, u32_t size, u8_t *src){ + SPIFFS_API_DBG_V("api_spiffs_write: 0x%08x len: %u\n", addr, size); + flashmem_write(src, addr, size); + return SPIFFS_OK; +} + +//SPIFFS API Erase CallBack +static s32_t api_spiffs_erase(u32_t addr, u32_t size){ + SPIFFS_API_DBG_V("api_spiffs_erase: 0x%08x len: %u\n", addr, size); + u32_t sect_first = flashmem_get_sector_of_address(addr); + u32_t sect_last = flashmem_get_sector_of_address(addr+size); + while( sect_first <= sect_last ) + if( !flashmem_erase_sector( sect_first ++ ) ) + return SPIFFS_ERR_INTERNAL; + return SPIFFS_OK; +} + +// Our own SPIFFS Setup Method +// All of the above gets put in the configuration +// and a mount attempt is made, initializing the storage handle +// that is used in all further api calls +s32_t spiffs_mount(){ + u32_t start_address = (u32_t)&_SPIFFS_start; + u32_t end_address = (u32_t)&_SPIFFS_end; + if (start_address == 0 || start_address >= end_address){ + SPIFFS_API_DBG_E("Can't start file system, wrong address"); + return SPIFFS_ERR_NOT_CONFIGURED; + } + + spiffs_config cfg = {0}; + cfg.phys_addr = start_address; + cfg.phys_size = end_address - start_address; + cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet + cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE * 2; // Important to make large + cfg.log_page_size = INTERNAL_FLASH_PAGE_SIZE; // according to datasheet + cfg.hal_read_f = api_spiffs_read; + cfg.hal_write_f = api_spiffs_write; + cfg.hal_erase_f = api_spiffs_erase; + + SPIFFS_API_DBG_V("spiffs_mount: start:%x, size:%d Kb\n", cfg.phys_addr, cfg.phys_size / 1024); + + s32_t res = SPIFFS_mount(&_filesystemStorageHandle, + &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + spiffs_cache, + sizeof(spiffs_cache), + NULL); + SPIFFS_API_DBG_V("spiffs_mount: %d\n", res); + return res; +} diff --git a/cores/esp8266/spiffs/spiffs_esp8266.h b/cores/esp8266/spiffs/spiffs_esp8266.h new file mode 100644 index 000000000..f36fbfbfe --- /dev/null +++ b/cores/esp8266/spiffs/spiffs_esp8266.h @@ -0,0 +1,40 @@ +#ifndef SYSTEM_FLASHMEM_H_ +#define SYSTEM_FLASHMEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "spiffs.h" + +/******************* +The W25Q32BV array is organized into 16,384 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time. +Pages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or +the entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 64 erasable blocks respectively. +The small 4KB sectors allow for greater flexibility in applications that require data and parameter storage. +********************/ + +#define SPIFFS_API_DBG_V(fmt, ...) //os_printf(fmt, ##__VA_ARGS__) +#define SPIFFS_API_DBG_E(fmt, ...) //os_printf("ERROR: " fmt , ##__VA_ARGS__) + +#define INTERNAL_FLASH_PAGE_SIZE 256 +#define INTERNAL_FLASH_SECTOR_SIZE 4096 +#define INTERNAL_FLASH_START_ADDRESS 0x40200000 + +#define INTERNAL_FLASH_WRITE_UNIT_SIZE 4 +#define INTERNAL_FLASH_READ_UNIT_SIZE 4 + +extern spiffs _filesystemStorageHandle; + +extern uint32_t flashmem_write( const void *from, uint32_t toaddr, uint32_t size ); +extern uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ); +extern bool flashmem_erase_sector( uint32_t sector_id ); +uint32_t flashmem_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend ); +uint32_t flashmem_get_sector_of_address( uint32_t addr ); +s32_t spiffs_mount(); + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_FLASHMEM_H_ */ diff --git a/cores/esp8266/spiffs/spiffs_flashmem.c b/cores/esp8266/spiffs/spiffs_flashmem.c deleted file mode 100755 index 156e2fac2..000000000 --- a/cores/esp8266/spiffs/spiffs_flashmem.c +++ /dev/null @@ -1,224 +0,0 @@ -#include "flashmem.h" -#include "esp8266_peri.h" - -// Based on NodeMCU platform_flash -// https://github.com/nodemcu/nodemcu-firmware - -extern uint32_t _SPIFFS_start; - -uint32_t flashmem_write( const void *from, uint32_t toaddr, uint32_t size ) -{ - uint32_t temp, rest, ssize = size; - unsigned i; - char tmpdata[ INTERNAL_FLASH_WRITE_UNIT_SIZE ]; - const uint8_t *pfrom = ( const uint8_t* )from; - const uint32_t blksize = INTERNAL_FLASH_WRITE_UNIT_SIZE; - const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1; - - // Align the start - if( toaddr & blkmask ) - { - rest = toaddr & blkmask; - temp = toaddr & ~blkmask; // this is the actual aligned address - // c_memcpy( tmpdata, ( const void* )temp, blksize ); - flashmem_read_internal( tmpdata, temp, blksize ); - for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ ) - tmpdata[ i ] = *pfrom; - flashmem_write_internal( tmpdata, temp, blksize ); - if( size == 0 ) - return ssize; - toaddr = temp + blksize; - } - // The start address is now a multiple of blksize - // Compute how many bytes we can write as multiples of blksize - rest = size & blkmask; - temp = size & ~blkmask; - // Program the blocks now - if( temp ) - { - flashmem_write_internal( pfrom, toaddr, temp ); - toaddr += temp; - pfrom += temp; - } - // And the final part of a block if needed - if( rest ) - { - // c_memcpy( tmpdata, ( const void* )toaddr, blksize ); - flashmem_read_internal( tmpdata, toaddr, blksize ); - for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ ) - tmpdata[ i ] = *pfrom; - flashmem_write_internal( tmpdata, toaddr, blksize ); - } - return ssize; -} - -uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ) -{ - uint32_t temp, rest, ssize = size; - unsigned i; - char tmpdata[ INTERNAL_FLASH_READ_UNIT_SIZE ]; - uint8_t *pto = ( uint8_t* )to; - const uint32_t blksize = INTERNAL_FLASH_READ_UNIT_SIZE; - const uint32_t blkmask = INTERNAL_FLASH_READ_UNIT_SIZE - 1; - - // Align the start - if( fromaddr & blkmask ) - { - rest = fromaddr & blkmask; - temp = fromaddr & ~blkmask; // this is the actual aligned address - flashmem_read_internal( tmpdata, temp, blksize ); - for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ ) - *pto = tmpdata[ i ]; - - if( size == 0 ) - return ssize; - fromaddr = temp + blksize; - } - // The start address is now a multiple of blksize - // Compute how many bytes we can read as multiples of blksize - rest = size & blkmask; - temp = size & ~blkmask; - // Program the blocks now - if( temp ) - { - flashmem_read_internal( pto, fromaddr, temp ); - fromaddr += temp; - pto += temp; - } - // And the final part of a block if needed - if( rest ) - { - flashmem_read_internal( tmpdata, fromaddr, blksize ); - for( i = 0; size && ( i < rest ); i ++, size --, pto ++ ) - *pto = tmpdata[ i ]; - } - return ssize; -} - -bool flashmem_erase_sector( uint32_t sector_id ) -{ - WRITE_PERI_REG(0x60000914, 0x73); - return spi_flash_erase_sector( sector_id ) == SPI_FLASH_RESULT_OK; -} - -SPIFlashInfo flashmem_get_info() -{ - volatile SPIFlashInfo spi_flash_info STORE_ATTR; - spi_flash_info = *((SPIFlashInfo *)(INTERNAL_FLASH_START_ADDRESS)); - return spi_flash_info; -} - -uint8_t flashmem_get_size_type() -{ - return flashmem_get_info().size; -} - -uint32_t flashmem_get_size_bytes() -{ - uint32_t flash_size = 0; - switch (flashmem_get_info().size) - { - case SIZE_2MBIT: - // 2Mbit, 256kByte - flash_size = 256 * 1024; - break; - case SIZE_4MBIT: - // 4Mbit, 512kByte - flash_size = 512 * 1024; - break; - case SIZE_8MBIT: - // 8Mbit, 1MByte - flash_size = 1 * 1024 * 1024; - break; - case SIZE_16MBIT: - // 16Mbit, 2MByte - flash_size = 2 * 1024 * 1024; - break; - case SIZE_32MBIT: - // 32Mbit, 4MByte - flash_size = 4 * 1024 * 1024; - break; - default: - // Unknown flash size, fall back mode. - flash_size = 512 * 1024; - break; - } - return flash_size; -} - -uint16_t flashmem_get_size_sectors() -{ - return flashmem_get_size_bytes() / SPI_FLASH_SEC_SIZE; -} - -// Helper function: find the flash sector in which an address resides -// Return the sector number, as well as the start and end address of the sector -uint32_t flashmem_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend ) -{ - address -= INTERNAL_FLASH_START_ADDRESS; - // All the sectors in the flash have the same size, so just align the address - uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE; - - if( pstart ) - *pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS; - if( pend ) - *pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS - 1; - return sect_id; -} - -uint32_t flashmem_get_sector_of_address( uint32_t addr ) -{ - return flashmem_find_sector( addr, NULL, NULL ); -} - -///////////////////////////////////////////////////// - -uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t size ) -{ - toaddr -= INTERNAL_FLASH_START_ADDRESS; - SpiFlashOpResult r; - const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1; - uint32_t *apbuf = NULL; - if( ((uint32_t)from) & blkmask ){ - apbuf = (uint32_t *)os_malloc(size); - if(!apbuf) - return 0; - os_memcpy(apbuf, from, size); - } - WDT_RESET(); - r = spi_flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); - if(apbuf) - os_free(apbuf); - if(SPI_FLASH_RESULT_OK == r) - return size; - else{ - SYSTEM_ERROR( "ERROR in flash_write: r=%d at %08X\n", ( int )r, ( unsigned )toaddr+INTERNAL_FLASH_START_ADDRESS ); - return 0; - } -} - -uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ) -{ - fromaddr -= INTERNAL_FLASH_START_ADDRESS; - SpiFlashOpResult r; - WDT_RESET(); - r = spi_flash_read(fromaddr, (uint32 *)to, size); - if(SPI_FLASH_RESULT_OK == r) - return size; - else{ - SYSTEM_ERROR( "ERROR in flash_read: r=%d at %08X\n", ( int )r, ( unsigned )fromaddr+INTERNAL_FLASH_START_ADDRESS ); - return 0; - } -} - -uint32_t flashmem_get_first_free_block_address(){ - if ((uint32_t)&_SPIFFS_start == 0){ - return 0; - } - debugf("_SPIFFS_start:%08x\n", (uint32_t)&_SPIFFS_start); - - // Round the total used flash size to the closest flash block address - uint32_t end; - flashmem_find_sector( (uint32_t)&_SPIFFS_start - 1, NULL, &end); - return end + 1; -} diff --git a/cores/esp8266/spiffs/spiffs_gc.c b/cores/esp8266/spiffs/spiffs_gc.c old mode 100755 new mode 100644 index 6145084dc..87e4faf90 --- a/cores/esp8266/spiffs/spiffs_gc.c +++ b/cores/esp8266/spiffs/spiffs_gc.c @@ -8,31 +8,11 @@ static s32_t spiffs_gc_erase_block( spiffs *fs, spiffs_block_ix bix) { s32_t res; - u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); - s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); SPIFFS_GC_DBG("gc: erase block %d\n", bix); - - // here we ignore res, just try erasing the block - while (size > 0) { - SPIFFS_GC_DBG("gc: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); - (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); - addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); - size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); - } - fs->free_blocks++; - - // register erase count for this block - res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, - SPIFFS_ERASE_COUNT_PADDR(fs, bix), - sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + res = spiffs_erase_block(fs, bix); SPIFFS_CHECK_RES(res); - fs->max_erase_count++; - if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { - fs->max_erase_count = 0; - } - #if SPIFFS_CACHE { u32_t i; @@ -119,17 +99,25 @@ s32_t spiffs_gc_check( spiffs *fs, u32_t len) { s32_t res; - u32_t free_pages = - (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count + s32_t free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2) - fs->stats_p_allocated - fs->stats_p_deleted; int tries = 0; if (fs->free_blocks > 3 && - len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) { + (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { return SPIFFS_OK; } - //printf("gcing started %d dirty, blocks %d free, want %d bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len); + u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); +// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { +// SPIFFS_GC_DBG("gc: full freeblk:%d needed:%d free:%d dele:%d\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); +// return SPIFFS_ERR_FULL; +// } + if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) { + SPIFFS_GC_DBG("gc_check: full freeblk:%d needed:%d free:%d dele:%d\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); + return SPIFFS_ERR_FULL; + } do { SPIFFS_GC_DBG("\ngc_check #%d: run gc free_blocks:%d pfree:%d pallo:%d pdele:%d [%d] len:%d of %d\n", @@ -140,18 +128,20 @@ s32_t spiffs_gc_check( spiffs_block_ix *cands; int count; spiffs_block_ix cand; - res = spiffs_gc_find_candidate(fs, &cands, &count); + s32_t prev_free_pages = free_pages; + // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state + res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0); SPIFFS_CHECK_RES(res); if (count == 0) { SPIFFS_GC_DBG("gc_check: no candidates, return\n"); - return res; + return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL; } #if SPIFFS_GC_STATS fs->stats_gc_runs++; #endif cand = cands[0]; fs->cleaning = 1; - //printf("gcing: cleaning block %d\n", cand); + //c_printf("gcing: cleaning block %d\n", cand); res = spiffs_gc_clean(fs, cand); fs->cleaning = 0; if (res < 0) { @@ -168,16 +158,28 @@ s32_t spiffs_gc_check( SPIFFS_CHECK_RES(res); free_pages = - (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) - fs->stats_p_allocated - fs->stats_p_deleted; - } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || - len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); - SPIFFS_GC_DBG("gc_check: finished\n"); + if (prev_free_pages <= 0 && prev_free_pages == free_pages) { + // abort early to reduce wear, at least tried once + SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n"); + break; + } - //printf("gcing finished %d dirty, blocks %d free, %d pages free, %d tries, res %d\n", - // fs->stats_p_allocated + fs->stats_p_deleted, - // fs->free_blocks, free_pages, tries, res); + } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || + (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs))); + + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + res = SPIFFS_ERR_FULL; + } + + SPIFFS_GC_DBG("gc_check: finished, %d dirty, blocks %d free, %d pages free, %d tries, res %d\n", + fs->stats_p_allocated + fs->stats_p_deleted, + fs->free_blocks, free_pages, tries, res); return res; } @@ -223,7 +225,8 @@ s32_t spiffs_gc_erase_page_stats( s32_t spiffs_gc_find_candidate( spiffs *fs, spiffs_block_ix **block_candidates, - int *candidate_count) { + int *candidate_count, + char fs_crammed) { s32_t res = SPIFFS_OK; u32_t blocks = fs->block_count; spiffs_block_ix cur_block = 0; @@ -249,6 +252,7 @@ s32_t spiffs_gc_find_candidate( while (res == SPIFFS_OK && blocks--) { u16_t deleted_pages_in_block = 0; u16_t used_pages_in_block = 0; + int obj_lookup_page = 0; // check each object lookup page while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { @@ -295,9 +299,9 @@ s32_t spiffs_gc_find_candidate( s32_t score = deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + used_pages_in_block * SPIFFS_GC_HEUR_W_USED + - erase_age * SPIFFS_GC_HEUR_W_ERASE_AGE; + erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); int cand_ix = 0; - SPIFFS_GC_DBG("\ngc_check: bix:%d del:%d use:%d score:%d\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); + SPIFFS_GC_DBG("gc_check: bix:%d del:%d use:%d score:%d\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); while (cand_ix < max_candidates) { if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { cand_blocks[cand_ix] = cur_block; diff --git a/cores/esp8266/spiffs/spiffs_hydrogen.c b/cores/esp8266/spiffs/spiffs_hydrogen.c old mode 100755 new mode 100644 index 36bdcd274..6601b61ad --- a/cores/esp8266/spiffs/spiffs_hydrogen.c +++ b/cores/esp8266/spiffs/spiffs_hydrogen.c @@ -21,6 +21,36 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) { #endif #endif +u8_t SPIFFS_mounted(spiffs *fs) { + return SPIFFS_CHECK_MOUNT(fs); +} + +s32_t SPIFFS_format(spiffs *fs) { + SPIFFS_API_CHECK_CFG(fs); + if (SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_MOUNTED; + return -1; + } + + s32_t res; + SPIFFS_LOCK(fs); + + spiffs_block_ix bix = 0; + while (bix < fs->block_count) { + fs->max_erase_count = 0; + res = spiffs_erase_block(fs, bix); + if (res != SPIFFS_OK) { + res = SPIFFS_ERR_ERASE_FAIL; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + bix++; + } + + SPIFFS_UNLOCK(fs); + + return 0; +} + s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, u8_t *fd_space, u32_t fd_space_size, void *cache, u32_t cache_size, @@ -34,10 +64,10 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, c_memset(fd_space, 0, fd_space_size); // align fd_space pointer to pointer size byte boundary, below is safe u8_t ptr_size = sizeof(void*); -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" - u8_t addr_lsb = (u8_t)(((u32_t)fd_space) & (ptr_size-1)); -// #pragma GCC diagnostic pop +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" + u8_t addr_lsb = ((u8_t)fd_space) & (ptr_size-1); +#pragma GCC diagnostic pop if (addr_lsb) { fd_space += (ptr_size-addr_lsb); fd_space_size -= (ptr_size-addr_lsb); @@ -46,10 +76,10 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, fs->fd_count = (fd_space_size/sizeof(spiffs_fd)); // align cache pointer to 4 byte boundary, below is safe -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" - addr_lsb = (u8_t)(((u32_t)cache) & (ptr_size-1)); -// #pragma GCC diagnostic pop +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" + addr_lsb = ((u8_t)cache) & (ptr_size-1); +#pragma GCC diagnostic pop if (addr_lsb) { u8_t *cache_8 = (u8_t *)cache; cache_8 += (ptr_size-addr_lsb); @@ -65,7 +95,16 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, spiffs_cache_init(fs); #endif - s32_t res = spiffs_obj_lu_scan(fs); + s32_t res; + +#if SPIFFS_USE_MAGIC + res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + fs->config_magic = SPIFFS_CONFIG_MAGIC; + + res = spiffs_obj_lu_scan(fs); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_DBG("page index byte len: %d\n", SPIFFS_CFG_LOG_PAGE_SZ(fs)); @@ -79,13 +118,15 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, fs->check_cb_f = check_cb_f; + fs->mounted = 1; + SPIFFS_UNLOCK(fs); return 0; } void SPIFFS_unmount(spiffs *fs) { - if (!SPIFFS_CHECK_MOUNT(fs)) return; + if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return; SPIFFS_LOCK(fs); u32_t i; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; @@ -98,16 +139,22 @@ void SPIFFS_unmount(spiffs *fs) { spiffs_fd_return(fs, cur_fd->file_nbr); } } - fs->block_count = 0; + fs->mounted = 0; + SPIFFS_UNLOCK(fs); } s32_t SPIFFS_errno(spiffs *fs) { - return fs->errno; + return fs->err_code; } -s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { +void SPIFFS_clearerr(spiffs *fs) { + fs->err_code = SPIFFS_OK; +} + +s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { (void)mode; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); spiffs_obj_id obj_id; @@ -121,8 +168,9 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { return 0; } -spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) { +spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode) { (void)mode; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -181,6 +229,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs } spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -209,7 +258,8 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl return fd->file_nbr; } -s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -277,7 +327,8 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs } -s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -314,8 +365,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { #endif } - SPIFFS_DBG("SPIFFS_write %d %04x offs:%d len %d\n", fh, fd->obj_id, offset, len); - #if SPIFFS_CACHE_WR if ((fd->flags & SPIFFS_DIRECT) == 0) { if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { @@ -328,12 +377,13 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page { // boundary violation, write back cache first and allocate new - SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:&04x, boundary viol, offs:%d size:%d\n", + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, boundary viol, offs:%d size:%d\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); res = spiffs_hydro_write(fs, fd, spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); } else { // writing within cache alloc_cpage = 0; @@ -379,6 +429,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); res = spiffs_hydro_write(fs, fd, buf, offset, len); SPIFFS_API_CHECK_RES(fs, res); } @@ -396,6 +447,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { } s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -439,7 +491,8 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { return 0; } -s32_t SPIFFS_remove(spiffs *fs, const char *path) { +s32_t SPIFFS_remove(spiffs *fs, char *path) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -473,6 +526,7 @@ s32_t SPIFFS_remove(spiffs *fs, const char *path) { } s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -520,7 +574,8 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi return res; } -s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { +s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -538,6 +593,7 @@ s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { } s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -580,7 +636,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); if (res < SPIFFS_OK) { - fs->errno = res; + fs->err_code = res; } spiffs_cache_fd_release(fs, fd->cache_page); } @@ -591,6 +647,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); s32_t res = SPIFFS_OK; #if SPIFFS_CACHE_WR @@ -604,8 +661,13 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { } void SPIFFS_close(spiffs *fs, spiffs_file fh) { + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return; + } + if (!SPIFFS_CHECK_MOUNT(fs)) { - fs->errno = SPIFFS_ERR_NOT_MOUNTED; + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return; } SPIFFS_LOCK(fs); @@ -618,7 +680,8 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh) { SPIFFS_UNLOCK(fs); } -s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname) { +s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -628,7 +691,7 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname) { s32_t res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)old, &pix_old); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)newname, &pix_dummy); + res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)new, &pix_dummy); if (res == SPIFFS_ERR_NOT_FOUND) { res = SPIFFS_OK; } else if (res == SPIFFS_OK) { @@ -645,7 +708,7 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname) { } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)newname, + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)new, 0, &pix_dummy); if (res != SPIFFS_OK) { @@ -658,12 +721,19 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newname) { return res; } -spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) { +spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) { (void)name; - if (!SPIFFS_CHECK_MOUNT(fs)) { - fs->errno = SPIFFS_ERR_NOT_MOUNTED; + + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; return 0; } + + if (!SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return 0; + } + d->fs = fs; d->block = 0; d->entry = 0; @@ -707,7 +777,7 @@ static s32_t spiffs_read_dir_v( struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { if (!SPIFFS_CHECK_MOUNT(d->fs)) { - d->fs->errno = SPIFFS_ERR_NOT_MOUNTED; + d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; } SPIFFS_LOCK(fs); @@ -732,19 +802,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { d->entry = entry + 1; ret = e; } else { - d->fs->errno = res; + d->fs->err_code = res; } SPIFFS_UNLOCK(fs); return ret; } s32_t SPIFFS_closedir(spiffs_DIR *d) { + SPIFFS_API_CHECK_CFG(d->fs); SPIFFS_API_CHECK_MOUNT(d->fs); return 0; } s32_t SPIFFS_check(spiffs *fs) { s32_t res; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -760,7 +832,32 @@ s32_t SPIFFS_check(spiffs *fs) { return res; } +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs); + u32_t blocks = fs->block_count; + u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs); + u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs); + u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page + + if (total) { + *total = total_data_pages * data_page_size; + } + + if (used) { + *used = fs->stats_p_allocated * data_page_size; + } + + SPIFFS_UNLOCK(fs); + return res; +} + s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -780,6 +877,7 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -801,6 +899,7 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { #if SPIFFS_TEST_VISUALISATION s32_t SPIFFS_vis(spiffs *fs) { s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -859,11 +958,14 @@ s32_t SPIFFS_vis(spiffs *fs) { } // per block spiffs_printf("era_cnt_max: %d\n", fs->max_erase_count); - spiffs_printf("last_errno: %d\n", fs->errno); + spiffs_printf("last_errno: %d\n", fs->err_code); spiffs_printf("blocks: %d\n", fs->block_count); spiffs_printf("free_blocks: %d\n", fs->free_blocks); spiffs_printf("page_alloc: %d\n", fs->stats_p_allocated); spiffs_printf("page_delet: %d\n", fs->stats_p_deleted); + u32_t total, used; + SPIFFS_info(fs, &total, &used); + spiffs_printf("used: %d of %d\n", used, total); SPIFFS_UNLOCK(fs); return res; diff --git a/cores/esp8266/spiffs/spiffs_nucleus.c b/cores/esp8266/spiffs/spiffs_nucleus.c old mode 100755 new mode 100644 index e58a9775e..fa75fd8e9 --- a/cores/esp8266/spiffs/spiffs_nucleus.c +++ b/cores/esp8266/spiffs/spiffs_nucleus.c @@ -142,9 +142,13 @@ s32_t spiffs_obj_lu_find_entry_visitor( cur_block++; cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs); if (cur_block >= fs->block_count) { - // block wrap - cur_block = 0; - cur_block_addr = 0; + if (flags & SPIFFS_VIS_NO_WRAP) { + return SPIFFS_VIS_END; + } else { + // block wrap + cur_block = 0; + cur_block_addr = 0; + } } } @@ -213,6 +217,45 @@ s32_t spiffs_obj_lu_find_entry_visitor( return SPIFFS_VIS_END; } +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); + s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + // here we ignore res, just try erasing the block + while (size > 0) { + SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); + size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); + } + fs->free_blocks++; + + // register erase count for this block + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_USE_MAGIC + // finally, write magic + spiffs_obj_id magic = SPIFFS_MAGIC(fs); + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_MAGIC_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&magic); + SPIFFS_CHECK_RES(res); +#endif + + fs->max_erase_count++; + if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { + fs->max_erase_count = 0; + } + + return res; +} + static s32_t spiffs_obj_lu_scan_v( spiffs *fs, @@ -238,40 +281,44 @@ static s32_t spiffs_obj_lu_scan_v( return SPIFFS_VIS_COUNTINUE; } + // Scans thru all obj lu and counts free, deleted and used pages // Find the maximum block erase count +// Checks magic if enabled s32_t spiffs_obj_lu_scan( spiffs *fs) { s32_t res; spiffs_block_ix bix; int entry; +#if SPIFFS_USE_MAGIC + spiffs_block_ix unerased_bix = (spiffs_block_ix)-1; +#endif - fs->free_blocks = 0; - fs->stats_p_allocated = 0; - fs->stats_p_deleted = 0; - - res = spiffs_obj_lu_find_entry_visitor(fs, - 0, - 0, - 0, - 0, - spiffs_obj_lu_scan_v, - 0, - 0, - &bix, - &entry); - - if (res == SPIFFS_VIS_END) { - res = SPIFFS_OK; - } - - SPIFFS_CHECK_RES(res); - + // find out erase count + // if enabled, check magic bix = 0; spiffs_obj_id erase_count_final; spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE; spiffs_obj_id erase_count_max = 0; while (bix < fs->block_count) { +#if SPIFFS_USE_MAGIC + spiffs_obj_id magic; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_MAGIC_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&magic); + + SPIFFS_CHECK_RES(res); + if (magic != SPIFFS_MAGIC(fs)) { + if (unerased_bix == (spiffs_block_ix)-1) { + // allow one unerased block as it might be powered down during an erase + unerased_bix = bix; + } else { + // more than one unerased block, bail out + SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS); + } + } +#endif spiffs_obj_id erase_count; res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, @@ -297,6 +344,38 @@ s32_t spiffs_obj_lu_scan( fs->max_erase_count = erase_count_final; +#if SPIFFS_USE_MAGIC + if (unerased_bix != (spiffs_block_ix)-1) { + // found one unerased block, remedy + SPIFFS_DBG("mount: erase block %d\n", bix); + res = spiffs_erase_block(fs, unerased_bix); + SPIFFS_CHECK_RES(res); + } +#endif + + // count blocks + + fs->free_blocks = 0; + fs->stats_p_allocated = 0; + fs->stats_p_deleted = 0; + + res = spiffs_obj_lu_find_entry_visitor(fs, + 0, + 0, + 0, + 0, + spiffs_obj_lu_scan_v, + 0, + 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + SPIFFS_CHECK_RES(res); + return res; } @@ -614,7 +693,7 @@ s32_t spiffs_object_create( spiffs_page_object_ix_header oix_hdr; int entry; - res = spiffs_gc_check(fs, 0); + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); obj_id |= SPIFFS_OBJ_ID_IX_FLAG; @@ -811,7 +890,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { s32_t res = SPIFFS_OK; u32_t written = 0; - res = spiffs_gc_check(fs, len); + SPIFFS_DBG("append: %d bytes @ offs %d of size %d\n", len, offset, fd->size); + + if (offset > fd->size) { + SPIFFS_DBG("append: offset reversed to size\n"); + offset = fd->size; + } + + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta + if (res != SPIFFS_OK) { + SPIFFS_DBG("append: gc check fail %d\n", res); + } SPIFFS_CHECK_RES(res); spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; @@ -912,7 +1001,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); SPIFFS_CHECK_RES(res); } - SPIFFS_DBG("append: %04x found object index at page %04x\n", fd->obj_id, pix); + SPIFFS_DBG("append: %04x found object index at page %04x [fd size %d]\n", fd->obj_id, pix, fd->size); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1003,8 +1092,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // update size in object header index page res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); - SPIFFS_DBG("append: %04x store new size II %d in objix_hdr, %04x:%04x, written %d\n", fd->obj_id - , offset+written, new_objix_hdr_page, 0, written); + SPIFFS_DBG("append: %04x store new size II %d in objix_hdr, %04x:%04x, written %d, res %d\n", fd->obj_id + , offset+written, new_objix_hdr_page, 0, written, res2); SPIFFS_CHECK_RES(res2); } else { // wrote within object index header page @@ -1042,7 +1131,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { s32_t res = SPIFFS_OK; u32_t written = 0; - res = spiffs_gc_check(fs, len); + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; @@ -1308,7 +1397,7 @@ s32_t spiffs_object_truncate( s32_t res = SPIFFS_OK; spiffs *fs = fd->fs; - res = spiffs_gc_check(fs, 0); + res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); spiffs_page_ix objix_pix = fd->objix_hdr_pix; @@ -1386,13 +1475,26 @@ s32_t spiffs_object_truncate( ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; } + SPIFFS_DBG("truncate: got data pix %04x\n", data_pix); + if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { // delete full data page res = spiffs_page_data_check(fs, fd, data_pix, data_spix); - if (res != SPIFFS_OK) break; + if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { + SPIFFS_DBG("truncate: err validating data pix %d\n", res); + break; + } + + if (res == SPIFFS_OK) { + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) { + SPIFFS_DBG("truncate: err deleting data pix %d\n", res); + break; + } + } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) { + res = SPIFFS_OK; + } - res = spiffs_page_delete(fs, data_pix); - if (res != SPIFFS_OK) break; // update current size if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) { cur_size -= SPIFFS_DATA_PAGE_SIZE(fs); diff --git a/cores/esp8266/spiffs/spiffs_nucleus.h b/cores/esp8266/spiffs/spiffs_nucleus.h old mode 100755 new mode 100644 index 9b10d9181..5d905fe90 --- a/cores/esp8266/spiffs/spiffs_nucleus.h +++ b/cores/esp8266/spiffs/spiffs_nucleus.h @@ -131,6 +131,10 @@ #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) +#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) + +#define SPIFFS_CONFIG_MAGIC (0x20090315) + #if SPIFFS_SINGLETON == 0 #define SPIFFS_CFG_LOG_PAGE_SZ(fs) \ ((fs)->cfg.log_page_size) @@ -189,9 +193,18 @@ // returns data size in a data page #define SPIFFS_DATA_PAGE_SIZE(fs) \ ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) ) -// returns physical address for block's erase count +// returns physical address for block's erase count, +// always in the physical last entry of the last object lookup page #define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \ ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) ) +// returns physical address for block's magic, +// always in the physical second last entry of the last object lookup page +#define SPIFFS_MAGIC_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 ) +// checks if there is any room for magic in the object luts +#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \ + ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \ + <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) ) // define helpers object @@ -238,7 +251,10 @@ #define SPIFFS_CHECK_MOUNT(fs) \ - ((fs)->block_count > 0) + ((fs)->mounted != 0) + +#define SPIFFS_CHECK_CFG(fs) \ + ((fs)->config_magic == SPIFFS_CONFIG_MAGIC) #define SPIFFS_CHECK_RES(res) \ do { \ @@ -247,19 +263,25 @@ #define SPIFFS_API_CHECK_MOUNT(fs) \ if (!SPIFFS_CHECK_MOUNT((fs))) { \ - (fs)->errno = SPIFFS_ERR_NOT_MOUNTED; \ + (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \ + return -1; \ + } + +#define SPIFFS_API_CHECK_CFG(fs) \ + if (!SPIFFS_CHECK_CFG((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \ return -1; \ } #define SPIFFS_API_CHECK_RES(fs, res) \ if ((res) < SPIFFS_OK) { \ - (fs)->errno = (res); \ + (fs)->err_code = (res); \ return -1; \ } #define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ if ((res) < SPIFFS_OK) { \ - (fs)->errno = (res); \ + (fs)->err_code = (res); \ SPIFFS_UNLOCK(fs); \ return -1; \ } @@ -381,6 +403,8 @@ typedef struct { // object structs // page header, part of each page except object lookup pages +// NB: this is always aligned when the data page is an object index, +// as in this case struct spiffs_page_object_ix is used typedef struct __attribute(( packed )) { // object id spiffs_obj_id obj_id; @@ -391,7 +415,11 @@ typedef struct __attribute(( packed )) { } spiffs_page_header; // object index header page header -typedef struct __attribute(( packed )) { +typedef struct __attribute(( packed )) +#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES + __attribute(( aligned(sizeof(spiffs_page_ix)) )) +#endif +{ // common page header spiffs_page_header p_hdr; // alignment @@ -400,8 +428,6 @@ typedef struct __attribute(( packed )) { u32_t size; // type of object spiffs_obj_type type; - // alignment2 - u8_t _align2[4 - (sizeof(spiffs_obj_type)&3)==0 ? 4 : (sizeof(spiffs_obj_type)&3)]; // name of object u8_t name[SPIFFS_OBJ_NAME_LEN]; } spiffs_page_object_ix_header; @@ -480,6 +506,10 @@ s32_t spiffs_obj_lu_find_entry_visitor( spiffs_block_ix *block_ix, int *lu_entry); +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix); + // --------------- s32_t spiffs_obj_lu_scan( @@ -627,7 +657,8 @@ s32_t spiffs_gc_erase_page_stats( s32_t spiffs_gc_find_candidate( spiffs *fs, spiffs_block_ix **block_candidate, - int *candidate_count); + int *candidate_count, + char fs_crammed); s32_t spiffs_gc_clean( spiffs *fs, diff --git a/doc/exception_causes.md b/doc/exception_causes.md new file mode 100644 index 000000000..4b11bdb13 --- /dev/null +++ b/doc/exception_causes.md @@ -0,0 +1,38 @@ +Exception Causes (EXCCAUSE) +=========================================== + +| EXC-CAUSE Code | Cause Name | Cause Description | Required Option | EXC-VADDR Loaded | +|:--------------:|:---------------------------|:------------------------------------------------------------------------------------------------------------|:-------------------------|:----------------:| +| 0 | IllegalInstructionCause | Illegal instruction | Exception | No | +| 1 | SyscallCause | SYSCALL instruction | Exception | No | +| 2 | InstructionFetchErrorCause | Processor internal physical address or data error during instruction fetch | Exception | Yes | +| 3 | LoadStoreErrorCause | Processor internal physical address or data error during load or store | Exception | Yes | +| 4 | Level1InterruptCause | Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register | Interrupt | No | +| 5 | AllocaCause | MOVSP instruction, if caller’s registers are not in the register file | Windowed Register | No | +| 6 | IntegerDivideByZeroCause | QUOS, QUOU, REMS, or REMU divisor operand is zero | 32-bit Integer Divide | No | +| 7 | Reserved for Tensilica | | | | +| 8 | PrivilegedCause | Attempt to execute a privileged operation when CRING ? 0 | MMU | No | +| 9 | LoadStoreAlignmentCause | Load or store to an unaligned address | Unaligned Exception | Yes | +| 10..11 | Reserved for Tensilica | | | | +| 12 | InstrPIFDataErrorCause | PIF data error during instruction fetch | Processor Interface | Yes | +| 13 | LoadStorePIFDataErrorCause | Synchronous PIF data error during LoadStore access | Processor Interface | Yes | +| 14 | InstrPIFAddrErrorCause | PIF address error during instruction fetch | Processor Interface | Yes | +| 15 | LoadStorePIFAddrErrorCause | Synchronous PIF address error during LoadStore access | Processor Interface | Yes | +| 16 | InstTLBMissCause | Error during Instruction TLB refill | MMU | Yes | +| 17 | InstTLBMultiHitCause | Multiple instruction TLB entries matched | MMU | Yes | +| 18 | InstFetchPrivilegeCause | An instruction fetch referenced a virtual address at a ring level less than CRING | MMU | Yes | +| 19 | Reserved for Tensilica | | | | +| 20 | InstFetchProhibitedCause | An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch | Region Protection or MMU | Yes | +| 21..23 | Reserved for Tensilica | | | | +| 24 | LoadStoreTLBMissCause | Error during TLB refill for a load or store | MMU | Yes | +| 25 | LoadStoreTLBMultiHitCause | Multiple TLB entries matched for a load or store | MMU | Yes | +| 26 | LoadStorePrivilegeCause | A load or store referenced a virtual address at a ring level less than CRING | MMU | Yes | +| 27 | Reserved for Tensilica | | | | +| 28 | LoadProhibitedCause | A load referenced a page mapped with an attribute that does not permit loads | Region Protection or MMU | Yes | +| 29 | StoreProhibitedCause | A store referenced a page mapped with an attribute that does not permit stores | Region Protection or MMU | Yes | +| 30..31 | Reserved for Tensilica | | | | +| 32..39 | CoprocessornDisabled | Coprocessor n instruction when cpn disabled. n varies 0..7 as the cause varies 32..39 | Coprocessor | No | +| 40..63 | Reserved | | | | + + +Infos from Xtensa Instruction Set Architecture (ISA) Reference Manual \ No newline at end of file diff --git a/libraries/EEPROM/EEPROM.cpp b/libraries/EEPROM/EEPROM.cpp index 74e7f3b0f..2d8b23db9 100644 --- a/libraries/EEPROM/EEPROM.cpp +++ b/libraries/EEPROM/EEPROM.cpp @@ -28,9 +28,10 @@ #include "os_type.h" #include "osapi.h" #include "spi_flash.h" +extern uint32_t _SPIFFS_end; } -#define CONFIG_START_SECTOR 0x7b +#define CONFIG_START_SECTOR (((uint32_t)_SPIFFS_end - 0x40200000) / 4096) #define CONFIG_SECTOR (CONFIG_START_SECTOR + 0) #define CONFIG_ADDR (SPI_FLASH_SEC_SIZE * CONFIG_SECTOR) @@ -41,7 +42,7 @@ EEPROMClass::EEPROMClass() void EEPROMClass::begin(size_t size) { - if (size < 0) + if (size <= 0) return; if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE; @@ -49,7 +50,9 @@ void EEPROMClass::begin(size_t size) _data = new uint8_t[size]; _size = size; + noInterrupts(); spi_flash_read(CONFIG_ADDR, reinterpret_cast(_data), _size); + interrupts(); } void EEPROMClass::end() @@ -58,8 +61,9 @@ void EEPROMClass::end() return; commit(); - - delete[] _data; + if(_data) { + delete[] _data; + } _data = 0; _size = 0; } @@ -69,6 +73,8 @@ uint8_t EEPROMClass::read(int address) { if (address < 0 || (size_t)address >= _size) return 0; + if(!_data) + return 0; return _data[address]; } @@ -77,6 +83,8 @@ void EEPROMClass::write(int address, uint8_t value) { if (address < 0 || (size_t)address >= _size) return; + if(!_data) + return; _data[address] = value; _dirty = true; @@ -89,20 +97,24 @@ bool EEPROMClass::commit() return false; if(!_dirty) return true; + if(!_data) + return false; - ETS_UART_INTR_DISABLE(); + noInterrupts(); if(spi_flash_erase_sector(CONFIG_SECTOR) == SPI_FLASH_RESULT_OK) { if(spi_flash_write(CONFIG_ADDR, reinterpret_cast(_data), _size) == SPI_FLASH_RESULT_OK) { _dirty = false; ret = true; } } - ETS_UART_INTR_ENABLE(); + interrupts(); + return ret; } uint8_t * EEPROMClass::getDataPtr() { + _dirty = true; return &_data[0]; } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 375d09600..d957e15ba 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -76,6 +76,20 @@ public: void sendHeader(String name, String value, bool first = false); void sendContent(String content); + +template size_t streamFile(T &file, String contentType){ + String head = "HTTP/1.1 200 OK\r\nContent-Type: "; + head += contentType; + head += "\r\nContent-Length: "; + head += file.size(); + head += "\r\nConnection: close"; + head += "\r\nAccess-Control-Allow-Origin: *"; + head += "\r\n\r\n"; + _currentClient.print(head); + head = String(); + return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE); +} + protected: void _handleRequest(); bool _parseRequest(WiFiClient& client); diff --git a/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino b/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino new file mode 100644 index 000000000..5a1057893 --- /dev/null +++ b/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino @@ -0,0 +1,33 @@ +/* + * This sketch trys to Connect to the best AP based on a given list + * + */ + +#include +#include + +ESP8266WiFiMulti WiFiMulti = ESP8266WiFiMulti(); + +void setup() { + Serial.begin(115200); + delay(10); + + WiFiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); + WiFiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); + WiFiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); + + Serial.println("Connecting Wifi..."); + if(wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + } +} + +void loop() { + if(wifiMulti.run() != WL_CONNECTED) { + Serial.println("WiFi not connected!"); + delay(1000); + } +} \ No newline at end of file diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index caf63982c..115b23763 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -81,6 +81,14 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase) return status(); } +uint8_t ESP8266WiFiClass::waitForConnectResult(){ + if ((wifi_get_opmode() & 1) == 0)//1 and 3 have STA enabled + return WL_DISCONNECTED; + while (status() == WL_DISCONNECTED) + delay(100); + return status(); +} + void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) { struct ip_info info; @@ -336,7 +344,7 @@ uint8_t ESP8266WiFiClass::encryptionType(uint8_t i) return -1; } -uint8_t ESP8266WiFiClass::status() +wl_status_t ESP8266WiFiClass::status() { int status = wifi_station_get_connect_status(); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/libraries/ESP8266WiFi/src/ESP8266WiFi.h index c98f32b8b..feb18abf8 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -58,6 +58,10 @@ public: */ int begin(const char* ssid, const char *passphrase); + /* Wait for Wifi connection to reach a result + * returns the status reached or disconnect if STA is off + */ + uint8_t waitForConnectResult(); /* Set up an open access point * @@ -195,7 +199,7 @@ public: * * return: one of the value defined in wl_status_t */ - uint8_t status(); + wl_status_t status(); /* * Resolve the given hostname to an IP address. diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp new file mode 100644 index 000000000..3b878020f --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -0,0 +1,171 @@ +/** + * + * @file ESP8266WiFiMulti.cpp + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * 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 + * + */ + +#include "ESP8266WiFiMulti.h" +#include + +ESP8266WiFiMulti::ESP8266WiFiMulti() { +} + +ESP8266WiFiMulti::~ESP8266WiFiMulti() { + APlistClean(); +} + +bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) { + return APlistAdd(ssid, passphrase); +} + +wl_status_t ESP8266WiFiMulti::run(void) { + + wl_status_t status = WiFi.status(); + if(status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) { + + WifiAPlist_t bestNetwork { NULL, NULL }; + int bestNetworkDb = INT_MIN; + + // WiFi.scanNetworks will return the number of networks found + int8_t n = WiFi.scanNetworks(); + + DEBUG_WIFI_MULTI("[WIFI] scan done\n"); + delay(0); + + if(n <= 0) { + DEBUG_WIFI_MULTI("[WIFI] no networks found\n"); + } else { + DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", n); + for(int8_t i = 0; i < n; ++i) { + const char * ssid_scan = WiFi.SSID(i); + int32_t rssi_scan = WiFi.RSSI(i); + uint8_t sec_scan = WiFi.encryptionType(i); + + bool known = false; + for(uint32_t x = 0; x < APlist.size(); x++) { + WifiAPlist_t entry = APlist[x]; + + if(strcmp(entry.ssid, ssid_scan) == 0) { // SSID match + known = true; + if(rssi_scan > bestNetworkDb) { // best network + if(sec_scan == ENC_TYPE_NONE || entry.passphrase) { // check for passphrase if not open wlan + bestNetworkDb = rssi_scan; + memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork)); + } + } + break; + } + } + + if(known) { + DEBUG_WIFI_MULTI(" ---> "); + } else { + DEBUG_WIFI_MULTI(" "); + } + + DEBUG_WIFI_MULTI(" %d: %s (%d) %c\n", i, ssid_scan, rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*'); + delay(0); + } + } + + DEBUG_WIFI_MULTI("\n\n"); + delay(0); + + if(bestNetwork.ssid) { + DEBUG_WIFI_MULTI("[WIFI] Connecting SSID: %s (%d)\n", bestNetwork.ssid, bestNetworkDb); + + WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase); + status = WiFi.status(); + + // wait for connection or fail + while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED) { + delay(10); + status = WiFi.status(); + } + + IPAddress ip; + switch(status) { + case WL_CONNECTED: + ip = WiFi.localIP(); + DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n"); + DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID()); + DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + break; + case WL_NO_SSID_AVAIL: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild AP not found.\n"); + break; + case WL_CONNECT_FAILED: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild.\n"); + break; + default: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild (%d).\n", status); + break; + } + } else { + DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n"); + } + } + return status; +} + +// ################################################################################## + +bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { + + WifiAPlist_t newAP; + + newAP.ssid = (char*) malloc(strlen(ssid)); + + if(!newAP.ssid) { + return false; + } + + strcpy(newAP.ssid, ssid); + + if(passphrase && *passphrase != 0x00) { + newAP.passphrase = (char*) malloc(strlen(passphrase)); + } + + if(!newAP.passphrase) { + free(newAP.ssid); + return false; + } + + strcpy(newAP.passphrase, passphrase); + + APlist.push_back(newAP); + return true; +} + +void ESP8266WiFiMulti::APlistClean(void) { + for(uint32_t i = 0; i < APlist.size(); i++) { + WifiAPlist_t entry = APlist[i]; + if(entry.ssid) { + free(entry.ssid); + } + if(entry.passphrase) { + free(entry.passphrase); + } + } + APlist.clear(); +} + diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h new file mode 100644 index 000000000..a3926a406 --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -0,0 +1,60 @@ +/** + * + * @file ESP8266WiFiMulti.h + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * 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 + * + */ + + +#ifndef WIFICLIENTMULTI_H_ +#define WIFICLIENTMULTI_H_ + +#include "ESP8266WiFi.h" +#include + +//#define DEBUG_WIFI_MULTI(...) os_printf( __VA_ARGS__ ) + +#ifndef DEBUG_WIFI_MULTI +#define DEBUG_WIFI_MULTI(...) +#endif + +typedef struct { + char * ssid; + char * passphrase; +} WifiAPlist_t; + +class ESP8266WiFiMulti { + public: + ESP8266WiFiMulti(); + ~ESP8266WiFiMulti(); + + bool addAP(const char* ssid, const char *passphrase = NULL); + + wl_status_t run(void); + + private: + std::vector APlist; + bool APlistAdd(const char* ssid, const char *passphrase = NULL); + void APlistClean(void); + +}; + +#endif /* WIFICLIENTMULTI_H_ */ diff --git a/libraries/ESP8266WiFi/src/include/wl_definitions.h b/libraries/ESP8266WiFi/src/include/wl_definitions.h index a32ba45b2..45bee6764 100644 --- a/libraries/ESP8266WiFi/src/include/wl_definitions.h +++ b/libraries/ESP8266WiFi/src/include/wl_definitions.h @@ -48,14 +48,14 @@ #define WL_MAX_ATTEMPT_CONNECTION 10 typedef enum { - WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library - WL_IDLE_STATUS = 0, - WL_NO_SSID_AVAIL, - WL_SCAN_COMPLETED, - WL_CONNECTED, - WL_CONNECT_FAILED, - WL_CONNECTION_LOST, - WL_DISCONNECTED + WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL = 1, + WL_SCAN_COMPLETED = 2, + WL_CONNECTED = 3, + WL_CONNECT_FAILED = 4, + WL_CONNECTION_LOST = 5, + WL_DISCONNECTED = 6 } wl_status_t; /* Encryption modes */ diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index 93c79138b..62276b4ee 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -106,6 +106,14 @@ public: boolean rmdir(char *filepath); + uint8_t type(){ return card.type(); } + uint8_t fatType(){ return volume.fatType(); } + size_t blocksPerCluster(){ return volume.blocksPerCluster(); } + size_t totalClusters(){ return volume.clusterCount(); } + size_t blockSize(){ return (size_t)0x200; } + size_t totalBlocks(){ return (totalClusters() / blocksPerCluster()); } + size_t clusterSize(){ return blocksPerCluster() * blockSize(); } + size_t size(){ return (clusterSize() * totalClusters()); } private: // This is used to determine the mode used to open a file diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index c96c4fcb8..7d52528ef 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -121,14 +121,14 @@ void SPIClass::setBitOrder(uint8_t bitOrder) { * @return */ static uint32_t ClkRegToFreq(spiClk_t * reg) { - return (F_CPU / ((reg->regPre + 1) * (reg->regN + 1))); + return (SPI_MAX_SPEED / ((reg->regPre + 1) * (reg->regN + 1))); } void SPIClass::setFrequency(uint32_t freq) { static uint32_t lastSetFrequency = 0; static uint32_t lastSetRegister = 0; - if(freq >= F_CPU) { + if(freq >= SPI_MAX_SPEED) { setClockDivider(0x80000000); return; } @@ -164,7 +164,7 @@ void SPIClass::setFrequency(uint32_t freq) { reg.regN = calN; while(calPreVari++ <= 1) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way) - calPre = (((F_CPU / (reg.regN + 1)) / freq) - 1) + calPreVari; + calPre = (((SPI_MAX_SPEED / (reg.regN + 1)) / freq) - 1) + calPreVari; if(calPre > 0x1FFF) { reg.regPre = 0x1FFF; // 8191 } else if(calPre <= 0) { diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index e67b5b0d5..68d2a3dc6 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -45,6 +45,8 @@ #define SPI_CLOCK_DIV64 0x04fc1001 //250 KHz #endif +#define SPI_MAX_SPEED (80000000L) + const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0 const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1 const uint8_t SPI_MODE2 = 0x10; ///< CPOL: 1 CPHA: 0 diff --git a/platform.txt b/platform.txt index bc4b20927..2df70eb14 100644 --- a/platform.txt +++ b/platform.txt @@ -15,7 +15,7 @@ compiler.sdk.path={compiler.tools.path}sdk/ compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" compiler.c.cmd=xtensa-lx106-elf-gcc -compiler.c.flags=-c -Os -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -MMD -std=c99 +compiler.c.flags=-c -Os -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=c99 compiler.S.cmd=xtensa-lx106-elf-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD @@ -25,7 +25,7 @@ compiler.c.elf.cmd=xtensa-lx106-elf-gcc compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig compiler.cpp.cmd=xtensa-lx106-elf-g++ -compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -std=c++11 -MMD +compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD compiler.as.cmd=xtensa-lx106-elf-as