diff --git a/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.cpp b/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.cpp old mode 100755 new mode 100644 index 802029a8d..735bb7d4a --- a/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.cpp +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.h b/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.h old mode 100755 new mode 100644 index 9d3a52eac..41659da11 --- a/hardware/esp8266com/esp8266/cores/esp8266/FileSystem.h +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/docs/INTEGRATION b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/INTEGRATION old mode 100755 new mode 100644 similarity index 99% rename from hardware/esp8266com/esp8266/cores/esp8266/spiffs/docs/INTEGRATION rename to hardware/esp8266com/esp8266/cores/esp8266/spiffs/INTEGRATION index 085ed8fc1..20ff70d05 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/docs/INTEGRATION +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/Makefile b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/Makefile deleted file mode 100755 index 1c44e4ace..000000000 --- a/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/README b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/README new file mode 100644 index 000000000..6efd656cb --- /dev/null +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/docs/TECH_SPEC b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/TECH_SPEC old mode 100755 new mode 100644 similarity index 100% rename from hardware/esp8266com/esp8266/cores/esp8266/spiffs/docs/TECH_SPEC rename to hardware/esp8266com/esp8266/cores/esp8266/spiffs/TECH_SPEC diff --git a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/TODO b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/TODO new file mode 100644 index 000000000..c947316a8 --- /dev/null +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/flashmem.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/flashmem.h deleted file mode 100755 index c4f4252a1..000000000 --- a/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.c deleted file mode 100755 index 74a65e05d..000000000 --- a/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h old mode 100755 new mode 100644 index 6357b44a7..7df7ae049 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_cache.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_cache.c old mode 100755 new mode 100644 diff --git a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_check.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_check.c old mode 100755 new mode 100644 index aad355122..50bbb5c89 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_check.c +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_config.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_config.h old mode 100755 new mode 100644 index 095bef900..d59ac80b1 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_config.h +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_esp8266.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_esp8266.c new file mode 100644 index 000000000..56cf3813c --- /dev/null +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_esp8266.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_esp8266.h new file mode 100644 index 000000000..f36fbfbfe --- /dev/null +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_flashmem.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_flashmem.c deleted file mode 100755 index dc875ff12..000000000 --- a/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_gc.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_gc.c old mode 100755 new mode 100644 index 6145084dc..87e4faf90 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_gc.c +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_hydrogen.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_hydrogen.c old mode 100755 new mode 100644 index 36bdcd274..6601b61ad --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_hydrogen.c +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.c b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.c old mode 100755 new mode 100644 index e58a9775e..fa75fd8e9 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.c +++ b/hardware/esp8266com/esp8266/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/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.h old mode 100755 new mode 100644 index 9b10d9181..5d905fe90 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs_nucleus.h +++ b/hardware/esp8266com/esp8266/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,