From ed77f2d42b5336cb0228119e22430d60ef2c494e Mon Sep 17 00:00:00 2001 From: Makuna Date: Thu, 14 May 2015 11:56:03 -0700 Subject: [PATCH 01/28] dtostrf fix for remainder leading zeros Fix remainder to display leading zeros --- cores/esp8266/core_esp8266_noniso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; } From b4a8bb0653311c8befebf2e011d310da11f32440 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Thu, 14 May 2015 21:41:43 +0200 Subject: [PATCH 02/28] fix bug when TX buffer is full and os will write. in this case we hang endless or until wtd triggers. new: now we overdrive the data in FIFO --> no hang / crash but we loss chars. only happens by extensive use of os_printf! --- cores/esp8266/HardwareSerial.cpp | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 87fd6dfbb..bdcd45716 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -392,30 +392,34 @@ 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; } + 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; } + if(c == '\n') { + USF(1) = '\r'; + } + USF(1) = c; } static int s_uart_debug_nr = UART0; From 2eea25873dbc2bc57aa9f6ff6f2c74f2eff855f2 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Fri, 15 May 2015 13:42:30 +0200 Subject: [PATCH 03/28] fix SPI speed calculation @160Mhz Clock --- libraries/SPI/SPI.cpp | 6 +++--- libraries/SPI/SPI.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) 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 From ea9368c88dadd6b16f2ef606d8ab6282de096a42 Mon Sep 17 00:00:00 2001 From: ficeto Date: Fri, 15 May 2015 20:06:13 +0300 Subject: [PATCH 04/28] enhance board flash handling and eeprom location --- boards.txt | 68 ++++++++++++++++++++++--------------- libraries/EEPROM/EEPROM.cpp | 3 +- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/boards.txt b/boards.txt index 4d6c41515..77f263cc6 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 @@ -197,6 +209,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/libraries/EEPROM/EEPROM.cpp b/libraries/EEPROM/EEPROM.cpp index 74e7f3b0f..14c6201f5 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) From 42f1da6b1f37d02d9bdc44a8f09935bf6f5dc558 Mon Sep 17 00:00:00 2001 From: ficeto Date: Fri, 15 May 2015 20:07:55 +0300 Subject: [PATCH 05/28] not needed menu item --- boards.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/boards.txt b/boards.txt index 77f263cc6..c1aad78e6 100644 --- a/boards.txt +++ b/boards.txt @@ -188,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 # From 1cd9cd312f36d63c7bedb811fb240d7b3cbecc2e Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 02:29:26 +0300 Subject: [PATCH 06/28] add folder api for SPIFFS --- cores/esp8266/FileSystem.cpp | 115 +++++++++++------- cores/esp8266/FileSystem.h | 9 +- .../ESP8266WebServer/src/ESP8266WebServer.h | 14 +++ 3 files changed, 95 insertions(+), 43 deletions(-) diff --git a/cores/esp8266/FileSystem.cpp b/cores/esp8266/FileSystem.cpp index ce722e7ec..1abd5dc9f 100755 --- a/cores/esp8266/FileSystem.cpp +++ b/cores/esp8266/FileSystem.cpp @@ -41,6 +41,10 @@ bool FSClass::format() { return spiffs_format(); } +bool FSClass::check() { + return SPIFFS_check(&_filesystemStorageHandle) == 0; +} + bool FSClass::exists(const char *filename) { spiffs_stat stat = {0}; if (SPIFFS_stat(&_filesystemStorageHandle, filename, &stat) < 0) @@ -61,6 +65,7 @@ bool FSClass::rename(const char *filename, const char *newname) { } FSFile FSClass::open(const char *filename, uint8_t mode) { + if(String(filename) == "" || String(filename) == "/") return FSFile("/"); int repeats = 0; bool notExist; bool canRecreate = (mode & SPIFFS_CREAT) == SPIFFS_CREAT; @@ -84,6 +89,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,88 +104,125 @@ 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, path.c_str(), (spiffs_flags)FSFILE_READ, 0); + if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ + debugf("stats 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)); + debugf("stats 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; } +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; - 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; + if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0) return 0; + return _stats.size; } uint32_t FSFile::seek(uint32_t pos) { - if (! _file) return 0; + if (! _file || isDirectory()) return 0; return SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); } uint32_t FSFile::position() { - if (! _file) return 0; + if (! _file || isDirectory()) return 0; return SPIFFS_tell(&_filesystemStorageHandle, _file); } bool FSFile::eof() { - if (! _file) return 0; + if (! _file || isDirectory()) return 0; return SPIFFS_eof(&_filesystemStorageHandle, _file); } bool FSFile::isDirectory(void) { - return false; + return _stats.type == SPIFFS_TYPE_DIR; } 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; + if (! _file || isDirectory()) 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; + return _stats.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); } @@ -191,24 +241,5 @@ void FSFile::clearError(){ } char * FSFile::name(){ - return 0; + return (char*)_stats.name; } - - - - - - -/* -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 index 460595cf3..8956300c1 100755 --- 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_RDWR | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_DIRECT) +#define FSFILE_OVERWRITE (SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC | SPIFFS_DIRECT) 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); @@ -54,6 +57,8 @@ public: 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; @@ -86,12 +91,14 @@ public: bool mount(); void unmount(); bool format(); + bool check(); bool exists(const char *filename); bool create(const char *filepath); bool remove(const char *filepath); bool rename(const char *filename, const char *newname); FSFile open(const char *filename, uint8_t mode = FSFILE_READ); + FSFile open(spiffs_dirent* entry, uint8_t mode = FSFILE_READ); private: friend class FSFile; 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); From 2c4307277699616d5ede927560ca3f4248d52034 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 11:03:39 +0300 Subject: [PATCH 07/28] enhancements on the FS Api --- cores/esp8266/FileSystem.cpp | 52 +++++++++++++++++++----------------- cores/esp8266/FileSystem.h | 6 ++--- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/cores/esp8266/FileSystem.cpp b/cores/esp8266/FileSystem.cpp index 1abd5dc9f..802029a8d 100755 --- a/cores/esp8266/FileSystem.cpp +++ b/cores/esp8266/FileSystem.cpp @@ -144,14 +144,22 @@ void FSFile::close() { _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; + if (!_file || !isDirectory()) return; SPIFFS_closedir(&_dir); SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); } FSFile FSFile::openNextFile(){ - if (! _file || !isDirectory()) return FSFile(); + if (!_file || !isDirectory()) return FSFile(); struct spiffs_dirent e; struct spiffs_dirent *pe = &e; if ((pe = SPIFFS_readdir(&_dir, pe))){ @@ -161,30 +169,36 @@ FSFile FSFile::openNextFile(){ } uint32_t FSFile::size() { - if(! _file) return 0; - if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0) 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); + _stats.size = SPIFFS_tell(&_filesystemStorageHandle, _file); + SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); 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 || isDirectory()) return 0; + if (!_file) return 0; return SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); } uint32_t FSFile::position() { - if (! _file || isDirectory()) return 0; + if (!_file) return 0; return SPIFFS_tell(&_filesystemStorageHandle, _file); } bool FSFile::eof() { - if (! _file || isDirectory()) return 0; + if (!_file) return 0; return SPIFFS_eof(&_filesystemStorageHandle, _file); } -bool FSFile::isDirectory(void) { - return _stats.type == SPIFFS_TYPE_DIR; -} - int FSFile::read(void *buf, uint16_t nbyte) { if (! _file || isDirectory()) return -1; return SPIFFS_read(&_filesystemStorageHandle, _file, buf, nbyte); @@ -204,12 +218,6 @@ int FSFile::peek() { return c; } -int FSFile::available() { - if (! _file || isDirectory()) return 0; - uint32_t pos = SPIFFS_tell(&_filesystemStorageHandle, _file); - return _stats.size - pos; -} - size_t FSFile::write(const uint8_t *buf, size_t size){ if (! _file || isDirectory()) return 0; int res = SPIFFS_write(&_filesystemStorageHandle, _file, (uint8_t *)buf, size); @@ -226,10 +234,10 @@ void FSFile::flush(){ 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, (const char *)_stats.name) == 0; } int FSFile::lastError(){ @@ -239,7 +247,3 @@ int FSFile::lastError(){ void FSFile::clearError(){ _filesystemStorageHandle.errno = SPIFFS_OK; } - -char * FSFile::name(){ - return (char*)_stats.name; -} diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h index 8956300c1..29173cb4e 100755 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -26,8 +26,8 @@ class String; #define FSFILE_READ SPIFFS_RDONLY -#define FSFILE_WRITE (SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_DIRECT) -#define FSFILE_OVERWRITE (SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC | SPIFFS_DIRECT) +#define FSFILE_WRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_DIRECT) +#define FSFILE_OVERWRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC | SPIFFS_DIRECT) class FSFile : public Stream { private: @@ -47,11 +47,11 @@ 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; } From b5b783e508b7dd8502290e17b9114e18fb588810 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 13:16:38 +0300 Subject: [PATCH 08/28] add access to SPIFFS properties --- cores/esp8266/FileSystem.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h index 29173cb4e..012bdc45b 100755 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -96,6 +96,13 @@ public: bool create(const char *filepath); bool remove(const char *filepath); bool rename(const char *filename, const char *newname); + 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(spiffs_dirent* entry, uint8_t mode = FSFILE_READ); From 5529188daeed70715ebf29e1799dcd13377301c3 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 16:22:38 +0300 Subject: [PATCH 09/28] add info methods to SD class --- libraries/SD/src/SD.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index 93c79138b..b0192dd2f 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -106,6 +106,14 @@ public: boolean rmdir(char *filepath); + size_t type(){ return card.type(); } + size_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 From 53cb1a014098dcf7cc3c109ebf8a980561058cb2 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 16:29:10 +0300 Subject: [PATCH 10/28] fix data types --- libraries/SD/src/SD.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index b0192dd2f..62276b4ee 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -106,8 +106,8 @@ public: boolean rmdir(char *filepath); - size_t type(){ return card.type(); } - size_t fatType(){ return volume.fatType(); } + 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; } From 0b168fd1bff8b5762fd933be701ccdc191b2aac5 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 18:25:22 +0300 Subject: [PATCH 11/28] add Print::printf --- cores/esp8266/Print.cpp | 11 +++++++++++ cores/esp8266/Print.h | 1 + 2 files changed, 12 insertions(+) diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index c1405c9f7..aa63cd290 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 = write((const char *)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[]); From 66d9dbb070b6f6ecea89571b212b17e80c47081c Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 19:00:36 +0300 Subject: [PATCH 12/28] ESP8266WiFiClass::waitForConnectResult() waitForConnectResult() waits until wifi status is not disconnected, unless STA is disabled, in which case it returns WL_DISCONNECTED --- libraries/ESP8266WiFi/src/ESP8266WiFi.cpp | 8 ++++++++ libraries/ESP8266WiFi/src/ESP8266WiFi.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index caf63982c..85a7ac416 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; diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/libraries/ESP8266WiFi/src/ESP8266WiFi.h index c98f32b8b..889af27a5 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 * From ab4629138331e004027a3b12c4d388f322856a21 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 20:38:00 +0300 Subject: [PATCH 13/28] fix uart triggering reset when spi has been read/written --- cores/esp8266/spiffs/spiffs_flashmem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cores/esp8266/spiffs/spiffs_flashmem.c b/cores/esp8266/spiffs/spiffs_flashmem.c index 156e2fac2..fff3c2a86 100755 --- a/cores/esp8266/spiffs/spiffs_flashmem.c +++ b/cores/esp8266/spiffs/spiffs_flashmem.c @@ -97,7 +97,7 @@ uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ) bool flashmem_erase_sector( uint32_t sector_id ) { - WRITE_PERI_REG(0x60000914, 0x73); + WDT_RESET(); return spi_flash_erase_sector( sector_id ) == SPI_FLASH_RESULT_OK; } @@ -186,7 +186,9 @@ uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t si os_memcpy(apbuf, from, size); } WDT_RESET(); + ETS_UART_INTR_DISABLE(); r = spi_flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); + ETS_UART_INTR_ENABLE(); if(apbuf) os_free(apbuf); if(SPI_FLASH_RESULT_OK == r) @@ -202,7 +204,9 @@ uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ) fromaddr -= INTERNAL_FLASH_START_ADDRESS; SpiFlashOpResult r; WDT_RESET(); + ETS_UART_INTR_DISABLE(); r = spi_flash_read(fromaddr, (uint32 *)to, size); + ETS_UART_INTR_ENABLE(); if(SPI_FLASH_RESULT_OK == r) return size; else{ From 62a460f0b81259e810124fee673d10463faf3ea9 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 20:39:23 +0300 Subject: [PATCH 14/28] printf to print instead of write --- cores/esp8266/Print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index aa63cd290..1f924248a 100644 --- a/cores/esp8266/Print.cpp +++ b/cores/esp8266/Print.cpp @@ -49,7 +49,7 @@ size_t Print::printf(const char *format, ...) { va_start(arg, format); char temp[256]; size_t len = ets_vsnprintf(temp, 256, format, arg); - len = write((const char *)temp); + len = print(temp); va_end(arg); return len; } From b902e86cb119020f959154fcaba498633cbb2a6e Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 21:01:51 +0300 Subject: [PATCH 15/28] disable all interrupts when reading from spiffs this fixes any possible resets caused by interrupt routines trying to read the flash while there is an ongoing spiffs operation --- cores/esp8266/Arduino.h | 2 +- cores/esp8266/spiffs/spiffs_flashmem.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) 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/spiffs/spiffs_flashmem.c b/cores/esp8266/spiffs/spiffs_flashmem.c index fff3c2a86..d7f182ee0 100755 --- a/cores/esp8266/spiffs/spiffs_flashmem.c +++ b/cores/esp8266/spiffs/spiffs_flashmem.c @@ -1,5 +1,6 @@ #include "flashmem.h" #include "esp8266_peri.h" +#include "Arduino.h" // Based on NodeMCU platform_flash // https://github.com/nodemcu/nodemcu-firmware @@ -98,7 +99,10 @@ uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ) bool flashmem_erase_sector( uint32_t sector_id ) { WDT_RESET(); - return spi_flash_erase_sector( sector_id ) == SPI_FLASH_RESULT_OK; + noInterrupts(); + bool erased = spi_flash_erase_sector( sector_id ) == SPI_FLASH_RESULT_OK; + interrupts(); + return erased; } SPIFlashInfo flashmem_get_info() @@ -186,9 +190,9 @@ uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t si os_memcpy(apbuf, from, size); } WDT_RESET(); - ETS_UART_INTR_DISABLE(); + noInterrupts(); r = spi_flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); - ETS_UART_INTR_ENABLE(); + interrupts(); if(apbuf) os_free(apbuf); if(SPI_FLASH_RESULT_OK == r) @@ -204,9 +208,9 @@ uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ) fromaddr -= INTERNAL_FLASH_START_ADDRESS; SpiFlashOpResult r; WDT_RESET(); - ETS_UART_INTR_DISABLE(); + noInterrupts(); r = spi_flash_read(fromaddr, (uint32 *)to, size); - ETS_UART_INTR_ENABLE(); + interrupts(); if(SPI_FLASH_RESULT_OK == r) return size; else{ From b6c196a49adb0d402a6cfae22d34c3f2ff3abdab Mon Sep 17 00:00:00 2001 From: ficeto Date: Sat, 16 May 2015 21:40:41 +0300 Subject: [PATCH 16/28] fix start address so erase works --- cores/esp8266/spiffs/spiffs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/spiffs/spiffs.c b/cores/esp8266/spiffs/spiffs.c index c07be839a..71d00905c 100755 --- a/cores/esp8266/spiffs/spiffs.c +++ b/cores/esp8266/spiffs/spiffs.c @@ -58,7 +58,7 @@ bool spiffs_format_internal(){ } u32_t sect_first, sect_last; - sect_first = flashmem_get_first_free_block_address(); + sect_first = flashmem_get_sector_of_address((u32_t)&_SPIFFS_start); 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 ){ From 108a40acfd3af5fd703b049c9b28dc9dd1a7d131 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sat, 16 May 2015 22:40:53 +0200 Subject: [PATCH 17/28] add support for list of AP connections - auto select ssid with best signal - for debugging enable DEBUG_WIFI_MULTI macro and call Serial.setDebugOutput(true); change ESP8266WiFiClass::status() return type to wl_status_t --- libraries/ESP8266WiFi/src/ESP8266WiFi.cpp | 2 +- libraries/ESP8266WiFi/src/ESP8266WiFi.h | 2 +- .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 167 ++++++++++++++++++ libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h | 59 +++++++ .../ESP8266WiFi/src/include/wl_definitions.h | 16 +- 5 files changed, 236 insertions(+), 10 deletions(-) create mode 100644 libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp create mode 100644 libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index caf63982c..9915d1bd6 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -336,7 +336,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..be257d152 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -195,7 +195,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..a284be754 --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -0,0 +1,167 @@ +/** + * + * @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 "ESP8266WiFi.h" +#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(); + } + + switch(status) { + case WL_CONNECTED: + DEBUG_WIFI_MULTI("[WIFI] Connecting Done.\n"); + 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..285fca755 --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -0,0 +1,59 @@ +/** + * + * @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 + +//#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 */ From 508f0802d5232929ccf88e542ae03a33c2928ce1 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sat, 16 May 2015 22:47:29 +0200 Subject: [PATCH 18/28] add examples/WiFiMulti/WiFiMulti.ino --- .../examples/WiFiMulti/WiFiMulti.ino | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino 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 From 03da6393d57c005af786fd7a16224694fcb614e3 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sat, 16 May 2015 22:56:15 +0200 Subject: [PATCH 19/28] improve includes add ssid and ip to debug out --- libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 8 ++++++-- libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index a284be754..3b878020f 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -23,7 +23,6 @@ * */ -#include "ESP8266WiFi.h" #include "ESP8266WiFiMulti.h" #include @@ -76,6 +75,7 @@ wl_status_t ESP8266WiFiMulti::run(void) { break; } } + if(known) { DEBUG_WIFI_MULTI(" ---> "); } else { @@ -102,9 +102,13 @@ wl_status_t ESP8266WiFiMulti::run(void) { status = WiFi.status(); } + IPAddress ip; switch(status) { case WL_CONNECTED: - DEBUG_WIFI_MULTI("[WIFI] Connecting Done.\n"); + 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"); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h index 285fca755..a3926a406 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -27,6 +27,7 @@ #ifndef WIFICLIENTMULTI_H_ #define WIFICLIENTMULTI_H_ +#include "ESP8266WiFi.h" #include //#define DEBUG_WIFI_MULTI(...) os_printf( __VA_ARGS__ ) From 4c4e6b8ce935fdb583333728dbd2e59494a61079 Mon Sep 17 00:00:00 2001 From: ficeto Date: Sun, 17 May 2015 00:04:39 +0300 Subject: [PATCH 20/28] spiffs fixes --- cores/esp8266/FileSystem.h | 4 ++-- cores/esp8266/spiffs/spiffs.c | 14 ++++++++------ cores/esp8266/spiffs/spiffs_flashmem.c | 18 +++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h index 012bdc45b..9d3a52eac 100755 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -26,8 +26,8 @@ class String; #define FSFILE_READ SPIFFS_RDONLY -#define FSFILE_WRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_DIRECT) -#define FSFILE_OVERWRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC | SPIFFS_DIRECT) +#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: diff --git a/cores/esp8266/spiffs/spiffs.c b/cores/esp8266/spiffs/spiffs.c index 71d00905c..74a65e05d 100755 --- a/cores/esp8266/spiffs/spiffs.c +++ b/cores/esp8266/spiffs/spiffs.c @@ -21,7 +21,7 @@ static s32_t api_spiffs_write(u32_t addr, u32_t size, u8_t *src){ 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; + 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; @@ -68,7 +68,7 @@ bool spiffs_format_internal(){ return true; } -bool spiffs_mount(){ +bool spiffs_mount_internal(bool wipe){ spiffs_config cfg = spiffs_get_storage_config(); if (cfg.phys_addr == 0){ SYSTEM_ERROR("Can't start file system, wrong address"); @@ -85,7 +85,7 @@ bool spiffs_mount(){ bool writeFirst = false; flashmem_read(&dat, cfg.phys_addr, 4); - if (dat == UINT32_MAX){ + if (dat == UINT32_MAX || wipe){ debugf("First init file system"); if(!spiffs_format_internal()){ SYSTEM_ERROR("Can't format file system"); @@ -115,15 +115,17 @@ bool spiffs_mount(){ return true; } +bool spiffs_mount(){ + return spiffs_mount_internal(false); +} + void spiffs_unmount(){ SPIFFS_unmount(&_filesystemStorageHandle); } bool spiffs_format(){ spiffs_unmount(); - if(!spiffs_format_internal()) return false; - spiffs_mount(); - return true; + return spiffs_mount_internal(true); } void test_spiffs(){ diff --git a/cores/esp8266/spiffs/spiffs_flashmem.c b/cores/esp8266/spiffs/spiffs_flashmem.c index d7f182ee0..dc875ff12 100755 --- a/cores/esp8266/spiffs/spiffs_flashmem.c +++ b/cores/esp8266/spiffs/spiffs_flashmem.c @@ -96,15 +96,6 @@ uint32_t flashmem_read( void *to, uint32_t fromaddr, uint32_t size ) return ssize; } -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; -} - SPIFlashInfo flashmem_get_info() { volatile SPIFlashInfo spi_flash_info STORE_ATTR; @@ -177,6 +168,15 @@ uint32_t flashmem_get_sector_of_address( uint32_t addr ) ///////////////////////////////////////////////////// +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; +} + uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t size ) { toaddr -= INTERNAL_FLASH_START_ADDRESS; From e50fc0fef8dd46e58483a66889f821c1d5fa3e7e Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sat, 16 May 2015 23:10:06 +0200 Subject: [PATCH 21/28] fix possible problems in EEPROM regarding interrupt handling and SPI flash blocking --- libraries/EEPROM/EEPROM.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/EEPROM/EEPROM.cpp b/libraries/EEPROM/EEPROM.cpp index 74e7f3b0f..2e1eb4fca 100644 --- a/libraries/EEPROM/EEPROM.cpp +++ b/libraries/EEPROM/EEPROM.cpp @@ -49,7 +49,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() @@ -90,19 +92,21 @@ bool EEPROMClass::commit() if(!_dirty) return true; - 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]; } From e0f9a4173eac7450758d02deac1d65857d2d2966 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 17 May 2015 13:33:10 +0200 Subject: [PATCH 22/28] force all os_malloc calls to request a aligned size. - this fix Fatal exception (9) by unaligned class memory --- cores/esp8266/abi.cpp | 2 ++ cores/esp8266/libc_replacements.c | 2 ++ 2 files changed, 4 insertions(+) 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/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); } From 5b5deb5a7784702b0c71a5bea1cfa15bac9b7256 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 17 May 2015 13:43:49 +0200 Subject: [PATCH 23/28] improve os_printf handling when buffer full. - wait for free buffer in hw fifo --- cores/esp8266/HardwareSerial.cpp | 46 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index bdcd45716..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; } @@ -400,6 +400,14 @@ void uart0_write_char(char c) { return; } } + + // wait for the Hardware FIFO + while(true) { + if(((USS(0) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { + break; + } + } + if(c == '\n') { USF(0) = '\r'; } @@ -416,6 +424,14 @@ void uart1_write_char(char c) { return; } } + + // wait for the Hardware FIFO + while(true) { + if(((USS(1) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { + break; + } + } + if(c == '\n') { USF(1) = '\r'; } @@ -469,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; From d15225430e0ecd419ee56c564e93381d58e7c80b Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 17 May 2015 13:53:31 +0200 Subject: [PATCH 24/28] Align the start of functions to the next power-of-two greater than 4, skipping up to 3 bytes. --- platform.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform.txt b/platform.txt index cd09aff98..9c197a832 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 @@ -26,7 +26,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 From a4adfab517a47eaa3e74f3ec28558eb5b2a40b9b Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 17 May 2015 13:54:03 +0200 Subject: [PATCH 25/28] fix possible null ptr in EEPROM.cpp --- libraries/EEPROM/EEPROM.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/EEPROM/EEPROM.cpp b/libraries/EEPROM/EEPROM.cpp index 2e1eb4fca..d0699c92e 100644 --- a/libraries/EEPROM/EEPROM.cpp +++ b/libraries/EEPROM/EEPROM.cpp @@ -41,7 +41,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; @@ -60,8 +60,9 @@ void EEPROMClass::end() return; commit(); - - delete[] _data; + if(_data) { + delete[] _data; + } _data = 0; _size = 0; } @@ -71,6 +72,8 @@ uint8_t EEPROMClass::read(int address) { if (address < 0 || (size_t)address >= _size) return 0; + if(!_data) + return 0; return _data[address]; } @@ -79,6 +82,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; @@ -91,6 +96,8 @@ bool EEPROMClass::commit() return false; if(!_dirty) return true; + if(!_data) + return false; noInterrupts(); if(spi_flash_erase_sector(CONFIG_SECTOR) == SPI_FLASH_RESULT_OK) { From 0be310f5b0b2042e0024e1ac500420c4efc08958 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 17 May 2015 14:55:11 +0200 Subject: [PATCH 26/28] add Exception Causes (EXCCAUSE) docu --- doc/exception_causes.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 doc/exception_causes.md 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 From ca88cb2b67265d745b652711fb400c408d8da585 Mon Sep 17 00:00:00 2001 From: ficeto Date: Mon, 18 May 2015 04:54:27 +0300 Subject: [PATCH 27/28] Update to the latest SPIFFS git and cleanup Almost unmodified spiffs from github lots of NodeMCU leftovers are removed More proper names given to platform related files Adjusting the FS class for the changes --- cores/esp8266/FileSystem.cpp | 70 ++++-- cores/esp8266/FileSystem.h | 13 +- cores/esp8266/spiffs/{docs => }/INTEGRATION | 2 +- cores/esp8266/spiffs/Makefile | 44 ---- cores/esp8266/spiffs/README | 86 ++++++++ cores/esp8266/spiffs/{docs => }/TECH_SPEC | 0 cores/esp8266/spiffs/TODO | 15 ++ cores/esp8266/spiffs/flashmem.h | 73 ------ cores/esp8266/spiffs/spiffs.c | 148 ------------- cores/esp8266/spiffs/spiffs.h | 112 +++++++--- cores/esp8266/spiffs/spiffs_cache.c | 0 cores/esp8266/spiffs/spiffs_check.c | 4 +- cores/esp8266/spiffs/spiffs_config.h | 44 ++-- cores/esp8266/spiffs/spiffs_esp8266.c | 224 +++++++++++++++++++ cores/esp8266/spiffs/spiffs_esp8266.h | 40 ++++ cores/esp8266/spiffs/spiffs_flashmem.c | 232 -------------------- cores/esp8266/spiffs/spiffs_gc.c | 80 +++---- cores/esp8266/spiffs/spiffs_hydrogen.c | 166 +++++++++++--- cores/esp8266/spiffs/spiffs_nucleus.c | 170 +++++++++++--- cores/esp8266/spiffs/spiffs_nucleus.h | 49 ++++- 20 files changed, 877 insertions(+), 695 deletions(-) mode change 100755 => 100644 cores/esp8266/FileSystem.cpp mode change 100755 => 100644 cores/esp8266/FileSystem.h rename cores/esp8266/spiffs/{docs => }/INTEGRATION (99%) mode change 100755 => 100644 delete mode 100755 cores/esp8266/spiffs/Makefile create mode 100644 cores/esp8266/spiffs/README rename cores/esp8266/spiffs/{docs => }/TECH_SPEC (100%) mode change 100755 => 100644 create mode 100644 cores/esp8266/spiffs/TODO delete mode 100755 cores/esp8266/spiffs/flashmem.h delete mode 100755 cores/esp8266/spiffs/spiffs.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs.h mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_cache.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_check.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_config.h create mode 100644 cores/esp8266/spiffs/spiffs_esp8266.c create mode 100644 cores/esp8266/spiffs/spiffs_esp8266.h delete mode 100755 cores/esp8266/spiffs/spiffs_flashmem.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_gc.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_hydrogen.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_nucleus.c mode change 100755 => 100644 cores/esp8266/spiffs/spiffs_nucleus.h diff --git a/cores/esp8266/FileSystem.cpp b/cores/esp8266/FileSystem.cpp old mode 100755 new mode 100644 index 802029a8d..735bb7d4a --- a/cores/esp8266/FileSystem.cpp +++ b/cores/esp8266/FileSystem.cpp @@ -22,49 +22,71 @@ #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::check() { return SPIFFS_check(&_filesystemStorageHandle) == 0; } -bool FSClass::exists(const char *filename) { +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; @@ -76,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 @@ -112,11 +134,11 @@ FSFile::FSFile(String path) { _stats.type = SPIFFS_TYPE_DIR; SPIFFS_opendir(&_filesystemStorageHandle, (char*)_stats.name, &_dir); } else { - _file = SPIFFS_open(&_filesystemStorageHandle, path.c_str(), (spiffs_flags)FSFILE_READ, 0); + _file = SPIFFS_open(&_filesystemStorageHandle, (char *)path.c_str(), (spiffs_flags)FSFILE_READ, 0); if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ - debugf("stats 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); + //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); } @@ -126,9 +148,9 @@ FSFile::FSFile(String path) { FSFile::FSFile(file_t f) { _file = f; if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ - debugf("stats 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); + //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); } @@ -237,7 +259,7 @@ void FSFile::flush(){ bool FSFile::remove(){ if (! _file) return 0; close(); - return SPIFFS_remove(&_filesystemStorageHandle, (const char *)_stats.name) == 0; + return SPIFFS_remove(&_filesystemStorageHandle, (char *)_stats.name) == 0; } int FSFile::lastError(){ @@ -245,5 +267,5 @@ int FSFile::lastError(){ } void FSFile::clearError(){ - _filesystemStorageHandle.errno = SPIFFS_OK; + _filesystemStorageHandle.err_code = SPIFFS_OK; } diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h old mode 100755 new mode 100644 index 9d3a52eac..41659da11 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -85,17 +85,18 @@ public: class FSClass { private: - bool _mounted = false; public: bool mount(); void unmount(); bool format(); bool check(); - bool exists(const char *filename); - bool create(const char *filepath); - bool remove(const char *filepath); - bool rename(const char *filename, const char *newname); + 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; } @@ -104,7 +105,7 @@ public: 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: 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/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 74a65e05d..000000000 --- a/cores/esp8266/spiffs/spiffs.c +++ /dev/null @@ -1,148 +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 = 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; -} - -/******************* -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_sector_of_address((u32_t)&_SPIFFS_start); - 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_internal(bool wipe){ - 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 || wipe){ - 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; -} - -bool spiffs_mount(){ - return spiffs_mount_internal(false); -} - -void spiffs_unmount(){ - SPIFFS_unmount(&_filesystemStorageHandle); -} - -bool spiffs_format(){ - spiffs_unmount(); - return spiffs_mount_internal(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 dc875ff12..000000000 --- a/cores/esp8266/spiffs/spiffs_flashmem.c +++ /dev/null @@ -1,232 +0,0 @@ -#include "flashmem.h" -#include "esp8266_peri.h" -#include "Arduino.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; -} - -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 ); -} - -///////////////////////////////////////////////////// - -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; -} - -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{ - 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(); - noInterrupts(); - r = spi_flash_read(fromaddr, (uint32 *)to, size); - interrupts(); - 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, From b5763e0e77b38224eb8a01073528bcf32b5e2c7c Mon Sep 17 00:00:00 2001 From: ficeto Date: Mon, 18 May 2015 04:57:34 +0300 Subject: [PATCH 28/28] leftovers --- cores/esp8266/spiffs/docs/IMPLEMENTING | 0 cores/esp8266/spiffs/docs/TODO | 1 - 2 files changed, 1 deletion(-) delete mode 100755 cores/esp8266/spiffs/docs/IMPLEMENTING delete mode 100755 cores/esp8266/spiffs/docs/TODO 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