1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-22 21:23:07 +03:00

Merge remote-tracking branch 'remotes/esp8266/esp8266' into esp8266

Conflicts:
	hardware/esp8266com/esp8266/cores/esp8266/Updater.cpp
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h
This commit is contained in:
Markus Sattler 2015-08-29 13:47:25 +02:00
commit 79bec479b5
34 changed files with 974 additions and 344 deletions

View File

@ -181,7 +181,7 @@ nodemcu.name=NodeMCU 0.9 (ESP-12 Module)
nodemcu.upload.tool=esptool
nodemcu.upload.speed=115200
nodemcu.upload.resetmethod=ck
nodemcu.upload.resetmethod=nodemcu
nodemcu.upload.maximum_size=1044464
nodemcu.upload.maximum_data_size=81920
nodemcu.upload.wait_for_upload_port=true

View File

@ -400,3 +400,26 @@ bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool
if(restartOnSuccess) ESP.restart();
return true;
}
static const int FLASH_INT_MASK = ((B10 << 8) | B00111010);
bool EspClass::flashEraseSector(uint32_t sector) {
ets_isr_mask(FLASH_INT_MASK);
int rc = spi_flash_erase_sector(sector);
ets_isr_unmask(FLASH_INT_MASK);
return rc == 0;
}
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
ets_isr_mask(FLASH_INT_MASK);
int rc = spi_flash_write(offset, (uint32_t*) data, size);
ets_isr_unmask(FLASH_INT_MASK);
return rc == 0;
}
bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) {
ets_isr_mask(FLASH_INT_MASK);
int rc = spi_flash_read(offset, (uint32_t*) data, size);
ets_isr_unmask(FLASH_INT_MASK);
return rc == 0;
}

View File

@ -117,6 +117,10 @@ class EspClass {
FlashMode_t getFlashChipMode();
uint32_t getFlashChipSizeByChipId();
bool flashEraseSector(uint32_t sector);
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
uint32_t getSketchSize();
uint32_t getFreeSketchSpace();
bool updateSketch(Stream& in, uint32_t size, bool restartOnFail = false, bool restartOnSuccess = true);

View File

@ -144,6 +144,14 @@ String Dir::fileName() {
return _impl->fileName();
}
size_t Dir::fileSize() {
if (!_impl) {
return 0;
}
return _impl->fileSize();
}
bool Dir::next() {
if (!_impl) {
return false;

View File

@ -78,6 +78,7 @@ public:
File openFile(const char* mode);
String fileName();
size_t fileSize();
bool next();
protected:

View File

@ -56,6 +56,7 @@ public:
virtual ~DirImpl() { }
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
virtual const char* fileName() = 0;
virtual size_t fileSize() = 0;
virtual bool next() = 0;
};

View File

@ -5,6 +5,11 @@
//#define DEBUG_UPDATER Serial
extern "C" {
#include "c_types.h"
#include "spi_flash.h"
}
extern "C" uint32_t _SPIFFS_start;
UpdaterClass::UpdaterClass()
@ -112,28 +117,14 @@ bool UpdaterClass::end(bool evenIfRemaining){
return true;
}
bool UpdaterClass::_writeBuffer() {
int rc = 0;
delay(2); // give the rtos some time to handle TCP
{
AutoInterruptLock(15);
rc = SPIEraseSector(_currentAddress / FLASH_SECTOR_SIZE);
}
bool UpdaterClass::_writeBuffer(){
yield();
bool result = ESP.flashEraseSector(_currentAddress/FLASH_SECTOR_SIZE) &&
ESP.flashWrite(_currentAddress, (uint32_t*) _buffer, _bufferLen);
delay(2); // give the rtos some time to handle TCP
if(!rc) {
{
AutoInterruptLock(15);
rc = SPIWrite(_currentAddress, _buffer, _bufferLen);
}
}
delay(2); // give the rtos some time to handle TCP
if(rc) {
_error = UPDATE_ERROR_WRITE;
_currentAddress = (_startAddress + _size);
if (!result) {
_error = UPDATE_ERROR_WRITE;
_currentAddress = (_startAddress + _size);
#ifdef DEBUG_UPDATER
printError(DEBUG_UPDATER);
#endif

View File

@ -148,6 +148,7 @@ char* ultoa(unsigned long value, char* result, int base) {
}
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
bool negative = false;
if (isnan(number)) {
strcpy(s, "nan");
@ -158,50 +159,65 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
return s;
}
if (number > 4294967040.0 || number < -4294967040.0) {
strcpy(s, "ovf");
return s;
}
char* out = s;
int signInt_Part = 1;
int fillme = width; // how many cells to fill for the integer part
if (prec > 0) {
fillme -= (prec+1);
}
// Handle negative numbers
if (number < 0.0) {
signInt_Part = -1;
negative = true;
fillme--;
number = -number;
}
// calc left over digits
if (prec > 0)
{
width -= (prec + 1);
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
// I optimized out most of the divisions
double rounding = 2.0;
for (uint8_t i = 0; i < prec; ++i)
rounding /= 10.0;
rounding *= 10.0;
rounding = 1.0 / rounding;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
out += sprintf(out, "%*ld", width, int_part * signInt_Part);
// Print the decimal point, but only if there are digits beyond
if (prec > 0) {
*out = '.';
++out;
for (unsigned char decShift = prec; decShift > 0; decShift--) {
remainder *= 10.0;
}
sprintf(out, "%0*d", prec, (int)remainder);
// Figure out how big our number really is
double tenpow = 1.0;
int digitcount = 1;
while (number >= 10.0 * tenpow) {
tenpow *= 10.0;
digitcount++;
}
number /= tenpow;
fillme -= digitcount;
// Pad unused cells with spaces
while (fillme-- > 0) {
*out++ = ' ';
}
// Handle negative sign
if (negative) *out++ = '-';
// Print the digits, and if necessary, the decimal point
digitcount += prec;
int8_t digit = 0;
while (digitcount-- > 0) {
digit = (int8_t)number;
if (digit > 9) digit = 9; // insurance
*out++ = (char)('0' | digit);
if ((digitcount == prec) && (prec > 0)) {
*out++ = '.';
}
number -= digit;
number *= 10.0;
}
// make sure the string is terminated
*out = 0;
return s;
}

View File

@ -1,5 +1,5 @@
SPIFFS (SPI Flash File System)
V0.3.0
V0.3.2
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
@ -58,6 +58,30 @@ For testing and contributions, see the docs/IMPLEMENTING file.
* HISTORY
0.3.2
Limit cache size if too much cache is given (thanks pgeiem)
New feature - Controlled erase. #23
SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
moved dbg print defines in test framework to params_test.h
lseek should return the resulting offset (thanks hefloryd)
fixed type on dbg ifdefs
silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
Cache might writethrough too often #16
even moar testrunner updates
Test framework update and some added tests
Some thoughts for next gen
Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
GC might be suboptimal #11
Fix eternal readdir when objheader at last block, last entry
New API functions:
SPIFFS_gc_quick - call a nonintrusive gc
SPIFFS_gc - call a full-scale intrusive gc
0.3.1
Removed two return warnings, was too triggerhappy on release
0.3.0
Added existing namecheck when creating files
Lots of static analysis bugs #6

View File

@ -9,7 +9,7 @@
#ifndef SPIFFS_H_
#define SPIFFS_H_
#ifdef __cplusplus
#if defined(__cplusplus)
extern "C" {
#endif
@ -47,6 +47,9 @@ extern "C" {
#define SPIFFS_ERR_ERASE_FAIL -10027
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
#define SPIFFS_ERR_FILE_EXISTS -10030
#define SPIFFS_ERR_INTERNAL -10050
@ -62,12 +65,25 @@ typedef u16_t spiffs_mode;
// object type
typedef u8_t spiffs_obj_type;
#if SPIFFS_HAL_CALLBACK_EXTRA
struct spiffs_t;
/* spi read call function type */
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
/* spi write call function type */
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
/* spi erase call function type */
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
#else // SPIFFS_HAL_CALLBACK_EXTRA
/* spi read call function type */
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
/* spi write call function type */
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
/* spi erase call function type */
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
#endif // SPIFFS_HAL_CALLBACK_EXTRA
/* file system check callback report operation */
typedef enum {
@ -88,21 +104,26 @@ typedef enum {
} spiffs_check_report;
/* file system check callback function */
#if SPIFFS_HAL_CALLBACK_EXTRA
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
u32_t arg1, u32_t arg2);
#else // SPIFFS_HAL_CALLBACK_EXTRA
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
u32_t arg1, u32_t arg2);
#endif // SPIFFS_HAL_CALLBACK_EXTRA
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) \
print(__VA_ARGS__)
#endif
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) c_printf(__VA_ARGS__)
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
#endif
#ifndef SPIFFS_CACHE_DBG
#define SPIFFS_CACHE_DBG(...) c_printf(__VA_ARGS__)
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
#endif
#ifndef SPIFFS_CHECK_DBG
#define SPIFFS_CHECK_DBG(...) c_printf(__VA_ARGS__)
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
#endif
/* Any write to the filehandle is appended to end of the file */
@ -119,6 +140,8 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
/* Any writes to the filehandle will never be cached */
#define SPIFFS_DIRECT (1<<5)
/* If SPIFFS_CREAT and SPIFFS_EXCL are set, SPIFFS_open() shall fail if the file exists */
#define SPIFFS_EXCL (1<<6)
#define SPIFFS_SEEK_SET (0)
#define SPIFFS_SEEK_CUR (1)
@ -166,7 +189,7 @@ typedef struct {
#endif
} spiffs_config;
typedef struct {
typedef struct spiffs_t {
// file system configuration
spiffs_config cfg;
// number of logical blocks
@ -224,6 +247,8 @@ typedef struct {
// mounted flag
u8_t mounted;
// user data
void *user_data;
// config magic
u32_t config_magic;
} spiffs;
@ -387,7 +412,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
* @param fs the file system struct
* @param fh the filehandle of the file to close
*/
void SPIFFS_close(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
/**
* Renames a file
@ -440,7 +465,6 @@ 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
@ -465,27 +489,60 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
* SPIFFS_format.
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
* SPIFFS_unmount first.
*
* @param fs the file system struct
*/
s32_t SPIFFS_format(spiffs *fs);
/**
* Returns nonzero if spiffs is mounted, or zero if unmounted.
* @param fs the file system struct
*/
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
* Tries to find a block where most or all pages are deleted, and erase that
* block if found. Does not care for wear levelling. Will not move pages
* around.
* If parameter max_free_pages are set to 0, only blocks with only deleted
* pages will be selected.
*
* NB: the garbage collector is automatically called when spiffs needs free
* pages. The reason for this function is to give possibility to do background
* tidying when user knows the system is idle.
*
* Use with care.
*
* Setting max_free_pages to anything larger than zero will eventually wear
* flash more as a block containing free pages can be erased.
*
* Will set err_no to SPIFFS_OK if a block was found and erased,
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
* or other error.
*
* @param fs the file system struct
* @param max_free_pages maximum number allowed free pages in block
*/
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
/**
* Get the current position of the data pointer.
* Will try to make room for given amount of bytes in the filesystem by moving
* pages and erasing blocks.
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
* there already is this amount (or more) of free space, SPIFFS_gc will
* silently return. It is recommended to call SPIFFS_info before invoking
* this method in order to determine what amount of bytes to give.
*
* NB: the garbage collector is automatically called when spiffs needs free
* pages. The reason for this function is to give possibility to do background
* tidying when user knows the system is idle.
*
* Use with care.
*
* @param fs the file system struct
* @param fh the filehandle of the open file
* @param size amount of bytes that should be freed
*/
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
#if SPIFFS_TEST_VISUALISATION
/**
@ -511,8 +568,9 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
#endif
#endif
#ifdef __cplusplus
#if SPIFFS_CACHE
#endif
#if defined(__cplusplus)
}
#endif

View File

@ -20,7 +20,7 @@ static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix)
if ((cache->cpage_use_map & (1<<i)) &&
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
cp->pix == pix ) {
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %d for %04x\n", i, pix);
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix);
cp->last_access = cache->last_access;
return cp;
}
@ -39,16 +39,16 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
}
cp->flags = 0;
cache->cpage_use_map &= ~(1 << ix);
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %d objid %04x\n", ix, cp->obj_id);
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id);
} else {
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %d pix %04x\n", ix, cp->pix);
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix);
}
}
@ -98,7 +98,7 @@ static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
cache->cpage_use_map |= (1<<i);
cp->last_access = cache->last_access;
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %d\n", i);
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i);
return cp;
}
}
@ -137,10 +137,7 @@ s32_t spiffs_phys_rd(
} else {
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
// for second layer lookup functions, we do not cache in order to prevent shredding
return fs->cfg.hal_read_f(
addr ,
len,
dst);
return SPIFFS_HAL_READ(fs, addr, len, dst);
}
#if SPIFFS_CACHE_STATS
fs->cache_misses++;
@ -151,8 +148,7 @@ s32_t spiffs_phys_rd(
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
}
s32_t res2 = fs->cfg.hal_read_f(
s32_t res2 = SPIFFS_HAL_READ(fs,
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
SPIFFS_CFG_LOG_PAGE_SZ(fs),
spiffs_get_cache_page(fs, cache, cp->ix));
@ -161,7 +157,7 @@ s32_t spiffs_phys_rd(
}
}
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
c_memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
return res;
}
@ -186,24 +182,24 @@ s32_t spiffs_phys_wr(
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
// page is being deleted, wipe from cache - unless it is a lookup page
spiffs_cache_page_free(fs, cp->ix, 0);
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
c_memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
cache->last_access++;
cp->last_access = cache->last_access;
if (cp->flags && SPIFFS_CACHE_FLAG_WRTHRU) {
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
// page is being updated, no write-cache, just pass thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
} else {
return SPIFFS_OK;
}
} else {
// no cache page, no write cache - just write thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
}
@ -282,17 +278,17 @@ void spiffs_cache_init(spiffs *fs) {
}
spiffs_cache cache;
c_memset(&cache, 0, sizeof(spiffs_cache));
memset(&cache, 0, sizeof(spiffs_cache));
cache.cpage_count = cache_entries;
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
cache.cpage_use_map = 0xffffffff;
cache.cpage_use_mask = cache_mask;
c_memcpy(fs->cache, &cache, sizeof(spiffs_cache));
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
spiffs_cache *c = spiffs_get_cache(fs);
c_memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
c->cpage_use_map &= ~(c->cpage_use_mask);
for (i = 0; i < cache.cpage_count; i++) {

View File

@ -22,6 +22,19 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#if SPIFFS_HAL_CALLBACK_EXTRA
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#else
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#endif
//---------------------------------------
// Look up consistency
@ -190,13 +203,13 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %d, cannot mend!\n", res);
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
res = spiffs_page_delete(fs, new_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
}
@ -216,7 +229,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
}
} else {
SPIFFS_CHECK_RES(res);
@ -249,12 +262,12 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %d, cannot mend!\n", res);
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
res = spiffs_page_delete(fs, new_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
}
SPIFFS_CHECK_RES(res);
}
@ -306,7 +319,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
@ -315,7 +328,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// rewrite as obj_id_lu
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
@ -353,7 +366,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only data page exists, make this page index
if (data_pix && objix_pix_d == 0) {
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
@ -369,7 +382,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only index exists, make data page
if (data_pix == 0 && objix_pix_d) {
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
@ -406,7 +419,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// page referenced by object index but not final
// just finalize
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
@ -418,7 +431,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
if (delete_page) {
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
@ -434,7 +447,7 @@ static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_bloc
spiffs_page_header p_hdr;
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
// load header
@ -460,7 +473,7 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
(void)check_all_objects;
s32_t res = SPIFFS_OK;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
@ -469,10 +482,10 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
@ -501,19 +514,22 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
// set this flag to abort all checks and rescan the page range
u8_t restart = 0;
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
spiffs_block_ix cur_block = 0;
// build consistency bitmap for id range traversing all blocks
while (!restart && cur_block < fs->block_count) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
0);
// traverse each page except for lookup pages
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
//if ((cur_pix & 0xff) == 0)
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
// read header
spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
@ -597,12 +613,12 @@ 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 %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);
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
// delete file
res = spiffs_page_delete(fs, cur_pix);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
@ -636,7 +652,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (data_pix == 0) {
// not found, this index is badly borked
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
break;
@ -647,11 +663,11 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
res = spiffs_rewrite_index(fs, p_hdr.obj_id, 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 %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);
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
@ -669,7 +685,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// the object which is referring to this page
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
p_hdr.obj_id, cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
// extra precaution, delete this page also
@ -763,20 +779,20 @@ 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 %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);
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
continue;
} else if (delete_page) {
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
}
SPIFFS_CHECK_RES(res);
@ -818,6 +834,8 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
}
}
}
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
// next page range
if (!restart) {
pix_offset += pages_per_scan;
@ -828,12 +846,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// Checks consistency amongst all pages and fixes irregularities
s32_t spiffs_page_consistency_check(spiffs *fs) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
s32_t res = spiffs_page_consistency_check_i(fs);
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
@ -862,7 +880,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
u32_t *log_ix = (u32_t *)user_p;
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
@ -879,7 +897,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
(SPIFFS_PH_FLAG_DELET)) {
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
return res_c;
@ -935,7 +953,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
if (delete) {
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
@ -956,18 +974,18 @@ s32_t spiffs_object_index_consistency_check(spiffs *fs) {
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
// a reachable/unreachable object id.
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
u32_t obj_id_log_ix = 0;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
0, 0);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}

View File

@ -9,7 +9,7 @@ static s32_t spiffs_gc_erase_block(
spiffs_block_ix bix) {
s32_t res;
SPIFFS_GC_DBG("gc: erase block %d\n", bix);
SPIFFS_GC_DBG("gc: erase block %i\n", bix);
res = spiffs_erase_block(fs, bix);
SPIFFS_CHECK_RES(res);
@ -28,7 +28,7 @@ static s32_t spiffs_gc_erase_block(
// the block is erased. Compared to the non-quick gc, the quick one ensures
// that no updates are needed on existing objects on pages that are erased.
s32_t spiffs_gc_quick(
spiffs *fs) {
spiffs *fs, u16_t max_free_pages) {
s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0;
@ -47,6 +47,7 @@ s32_t spiffs_gc_quick(
// check each block
while (res == SPIFFS_OK && blocks--) {
u16_t deleted_pages_in_block = 0;
u16_t free_pages_in_block = 0;
int obj_lookup_page = 0;
// check each object lookup page
@ -63,9 +64,12 @@ s32_t spiffs_gc_quick(
deleted_pages_in_block++;
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
// kill scan, go for next block
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
res = 1; // kill object lu loop
break;
free_pages_in_block++;
if (free_pages_in_block > max_free_pages) {
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
res = 1; // kill object lu loop
break;
}
} else {
// kill scan, go for next block
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
@ -78,7 +82,9 @@ s32_t spiffs_gc_quick(
} // per object lookup page
if (res == 1) res = SPIFFS_OK;
if (res == SPIFFS_OK && deleted_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
if (res == SPIFFS_OK &&
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
free_pages_in_block <= max_free_pages) {
// found a fully deleted block
fs->stats_p_deleted -= deleted_pages_in_block;
res = spiffs_gc_erase_block(fs, cur_block);
@ -90,10 +96,13 @@ s32_t spiffs_gc_quick(
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
} // per block
if (res == SPIFFS_OK) {
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
}
return res;
}
// Checks if garbaga collecting is necessary. If so a candidate block is found,
// Checks if garbage collecting is necessary. If so a candidate block is found,
// cleansed and erased
s32_t spiffs_gc_check(
spiffs *fs,
@ -111,16 +120,16 @@ s32_t spiffs_gc_check(
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);
// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\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);
SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\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",
SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
tries,
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
@ -141,13 +150,13 @@ s32_t spiffs_gc_check(
#endif
cand = cands[0];
fs->cleaning = 1;
//c_printf("gcing: cleaning block %d\n", cand);
//printf("gcing: cleaning block %i\n", cand);
res = spiffs_gc_clean(fs, cand);
fs->cleaning = 0;
if (res < 0) {
SPIFFS_GC_DBG("gc_check: cleaning block %d, result %d\n", cand, res);
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
} else {
SPIFFS_GC_DBG("gc_check: cleaning block %d, result %d\n", cand, res);
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
}
SPIFFS_CHECK_RES(res);
@ -177,7 +186,7 @@ s32_t spiffs_gc_check(
res = SPIFFS_ERR_FULL;
}
SPIFFS_GC_DBG("gc_check: finished, %d dirty, blocks %d free, %d pages free, %d tries, res %d\n",
SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
fs->stats_p_allocated + fs->stats_p_deleted,
fs->free_blocks, free_pages, tries, res);
@ -215,7 +224,7 @@ s32_t spiffs_gc_erase_page_stats(
} // per entry
obj_lookup_page++;
} // per object lookup page
SPIFFS_GC_DBG("gc_check: wipe pallo:%d pdele:%d\n", allo, dele);
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
fs->stats_p_allocated -= allo;
fs->stats_p_deleted -= dele;
return res;
@ -237,13 +246,18 @@ s32_t spiffs_gc_find_candidate(
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
*candidate_count = 0;
c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
// divide up work area into block indices and scores
// todo alignment?
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
// align cand_scores on s32_t boundary
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
cand_scores = (s32_t*)(((u32_t)cand_scores + sizeof(s32_t) - 1) & ~(sizeof(s32_t) - 1));
#pragma GCC diagnostic pop
*block_candidates = cand_blocks;
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
@ -301,7 +315,7 @@ s32_t spiffs_gc_find_candidate(
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
int cand_ix = 0;
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);
SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\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;
@ -370,20 +384,20 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
SPIFFS_GC_DBG("gc_clean: cleaning block %d\n", bix);
SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix);
c_memset(&gc, 0, sizeof(spiffs_gc));
memset(&gc, 0, sizeof(spiffs_gc));
gc.state = FIND_OBJ_DATA;
if (fs->free_cursor_block_ix == bix) {
// move free cursor to next block, cannot use free pages from the block we want to clean
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
fs->free_cursor_obj_lu_entry = 0;
SPIFFS_GC_DBG("gc_clean: move free cursor to block %d\n", fs->free_cursor_block_ix);
SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
}
while (res == SPIFFS_OK && gc.state != FINISHED) {
SPIFFS_GC_DBG("gc_clean: state = %d entry:%d\n", gc.state, cur_entry);
SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
gc.obj_id_found = 0;
// scan through lookup pages
@ -406,7 +420,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
case FIND_OBJ_DATA:
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%d - found obj id %04x\n", gc.state, obj_id);
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
gc.obj_id_found = 1;
gc.cur_obj_id = obj_id;
scan = 0;
@ -550,9 +564,10 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
cur_entry = 0;
break;
}
SPIFFS_GC_DBG("gc_clean: state-> %d\n", gc.state);
SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state);
} // while state != FINISHED
return res;
}

View File

@ -8,7 +8,9 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#if SPIFFS_CACHE == 1
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
#endif
#if SPIFFS_BUFFER_HELP
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
@ -56,12 +58,12 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
void *cache, u32_t cache_size,
spiffs_check_callback check_cb_f) {
SPIFFS_LOCK(fs);
c_memset(fs, 0, sizeof(spiffs));
c_memcpy(&fs->cfg, config, sizeof(spiffs_config));
memset(fs, 0, sizeof(spiffs));
memcpy(&fs->cfg, config, sizeof(spiffs_config));
fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
fs->work = &work[0];
fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
c_memset(fd_space, 0, fd_space_size);
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
@ -89,9 +91,10 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
if (cache_size & (ptr_size-1)) {
cache_size -= (cache_size & (ptr_size-1));
}
#if SPIFFS_CACHE
fs->cache = cache;
fs->cache_size = cache_size;
fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;
spiffs_cache_init(fs);
#endif
@ -107,14 +110,14 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
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));
SPIFFS_DBG("object lookup pages: %d\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
SPIFFS_DBG("page pages per block: %d\n", SPIFFS_PAGES_PER_BLOCK(fs));
SPIFFS_DBG("page header length: %d\n", sizeof(spiffs_page_header));
SPIFFS_DBG("object header index entries: %d\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
SPIFFS_DBG("object index entries: %d\n", SPIFFS_OBJ_IX_LEN(fs));
SPIFFS_DBG("available file descriptors: %d\n", fs->fd_count);
SPIFFS_DBG("free blocks: %d\n", fs->free_blocks);
SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs));
SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header));
SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs));
SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count);
SPIFFS_DBG("free blocks: %i\n", fs->free_blocks);
fs->check_cb_f = check_cb_f;
@ -188,6 +191,14 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
}
if (res == SPIFFS_OK &&
(flags & (SPIFFS_CREAT | SPIFFS_EXCL)) == (SPIFFS_CREAT | SPIFFS_EXCL)) {
// creat and excl and file exists - fail
res = SPIFFS_ERR_FILE_EXISTS;
spiffs_fd_return(fs, fd->file_nbr);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
}
if ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
spiffs_obj_id obj_id;
// no need to enter conflicting name here, already looked for it above
@ -377,7 +388,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_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 %i for fd %i:%04x, boundary viol, offs:%i size:%i\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),
@ -395,19 +406,19 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
if (fd->cache_page) {
fd->cache_page->offset = offset;
fd->cache_page->size = 0;
SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %d for fd %d:%04x\n",
SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %i for fd %i:%04x\n",
fd->cache_page->ix, fd->file_nbr, fd->obj_id);
}
}
if (fd->cache_page) {
u32_t offset_in_cpage = offset - fd->cache_page->offset;
SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %d for fd %d:%04x, offs %d:%d len %d\n",
SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %i for fd %i:%04x, offs %i:%i len %i\n",
fd->cache_page->ix, fd->file_nbr, fd->obj_id,
offset, offset_in_cpage, len);
spiffs_cache *cache = spiffs_get_cache(fs);
u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
c_memcpy(&cpage_data[offset_in_cpage], buf, len);
memcpy(&cpage_data[offset_in_cpage], buf, len);
fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
fd->fdoffset += len;
SPIFFS_UNLOCK(fs);
@ -423,7 +434,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
// big write, no need to cache it - but first check if there is a cached write already
if (fd->cache_page) {
// write back cache first
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, big write, offs:%d size:%d\n",
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, big write, offs:%i size:%i\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),
@ -488,7 +499,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
SPIFFS_UNLOCK(fs);
return 0;
return offs;
}
s32_t SPIFFS_remove(spiffs *fs, char *path) {
@ -554,6 +565,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
}
static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
(void)fh;
spiffs_page_object_ix_header objix_hdr;
spiffs_obj_id obj_id;
s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
@ -616,7 +628,10 @@ s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
// Checks if there are any cached writes for the object id associated with
// given filehandle. If so, these writes are flushed.
#if SPIFFS_CACHE == 1
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
(void)fs;
(void)fh;
s32_t res = SPIFFS_OK;
#if SPIFFS_CACHE_WR
@ -630,7 +645,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
}
if (fd->cache_page) {
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, flush, offs:%d size:%d\n",
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, flush, offs:%i size:%i\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),
@ -645,8 +660,10 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
return res;
}
#endif
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
(void)fh;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
s32_t res = SPIFFS_OK;
@ -660,24 +677,23 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
return res;
}
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
if (!SPIFFS_CHECK_CFG((fs))) {
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
return;
}
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return;
}
s32_t res = SPIFFS_OK;
SPIFFS_LOCK(fs);
#if SPIFFS_CACHE
spiffs_fflush_cache(fs, fh);
res = spiffs_fflush_cache(fs, fh);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
#endif
spiffs_fd_return(fs, fh);
res = spiffs_fd_return(fs, fh);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_UNLOCK(fs);
return res;
}
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
@ -711,9 +727,8 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
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) {
spiffs_fd_return(fs, fd->file_nbr);
}
spiffs_fd_return(fs, fd->file_nbr);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_UNLOCK(fs);
@ -780,7 +795,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return 0;
}
SPIFFS_LOCK(fs);
SPIFFS_LOCK(d->fs);
spiffs_block_ix bix;
int entry;
@ -804,7 +819,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
} else {
d->fs->err_code = res;
}
SPIFFS_UNLOCK(fs);
SPIFFS_UNLOCK(d->fs);
return ret;
}
@ -856,46 +871,34 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
return res;
}
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
s32_t res;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
s32_t res;
res = spiffs_fd_get(fs, fh, &fd);
SPIFFS_API_CHECK_RES(fs, res);
#if SPIFFS_CACHE_WR
spiffs_fflush_cache(fs, fh);
#endif
res = (fd->fdoffset == fd->size);
res = spiffs_gc_quick(fs, max_free_pages);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_UNLOCK(fs);
return res;
return 0;
}
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
s32_t res;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
s32_t res;
res = spiffs_fd_get(fs, fh, &fd);
SPIFFS_API_CHECK_RES(fs, res);
#if SPIFFS_CACHE_WR
spiffs_fflush_cache(fs, fh);
#endif
res = fd->fdoffset;
res = spiffs_gc_check(fs, size);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_UNLOCK(fs);
return res;
return 0;
}
#if SPIFFS_TEST_VISUALISATION
s32_t SPIFFS_vis(spiffs *fs) {
s32_t res = SPIFFS_OK;
@ -949,7 +952,7 @@ s32_t SPIFFS_vis(spiffs *fs) {
SPIFFS_CHECK_RES(res);
if (erase_count != (spiffs_obj_id)-1) {
spiffs_printf("\tera_cnt: %d\n", erase_count);
spiffs_printf("\tera_cnt: %i\n", erase_count);
} else {
spiffs_printf("\tera_cnt: N/A\n");
}
@ -957,15 +960,15 @@ s32_t SPIFFS_vis(spiffs *fs) {
bix++;
} // per block
spiffs_printf("era_cnt_max: %d\n", fs->max_erase_count);
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);
spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count);
spiffs_printf("last_errno: %i\n", fs->err_code);
spiffs_printf("blocks: %i\n", fs->block_count);
spiffs_printf("free_blocks: %i\n", fs->free_blocks);
spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated);
spiffs_printf("page_delet: %i\n", fs->stats_p_deleted);
u32_t total, used;
SPIFFS_info(fs, &total, &used);
spiffs_printf("used: %d of %d\n", used, total);
spiffs_printf("used: %i of %i\n", used, total);
SPIFFS_UNLOCK(fs);
return res;

View File

@ -64,7 +64,7 @@ s32_t spiffs_phys_rd(
u32_t addr,
u32_t len,
u8_t *dst) {
return fs->cfg.hal_read_f(addr, len, dst);
return SPIFFS_HAL_READ(fs, addr, len, dst);
}
s32_t spiffs_phys_wr(
@ -72,7 +72,7 @@ s32_t spiffs_phys_wr(
u32_t addr,
u32_t len,
u8_t *src) {
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
#endif
@ -83,6 +83,7 @@ s32_t spiffs_phys_cpy(
u32_t dst,
u32_t src,
u32_t len) {
(void)fh;
s32_t res;
u8_t b[SPIFFS_COPY_BUFFER_STACK];
while (len > 0) {
@ -227,7 +228,8 @@ s32_t spiffs_erase_block(
// 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));
SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
}
@ -347,7 +349,7 @@ s32_t spiffs_obj_lu_scan(
#if SPIFFS_USE_MAGIC
if (unerased_bix != (spiffs_block_ix)-1) {
// found one unerased block, remedy
SPIFFS_DBG("mount: erase block %d\n", bix);
SPIFFS_DBG("mount: erase block %i\n", bix);
res = spiffs_erase_block(fs, unerased_bix);
SPIFFS_CHECK_RES(res);
}
@ -389,7 +391,10 @@ s32_t spiffs_obj_lu_find_free(
int *lu_entry) {
s32_t res;
if (!fs->cleaning && fs->free_blocks < 2) {
res = spiffs_gc_quick(fs);
res = spiffs_gc_quick(fs, 0);
if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {
res = SPIFFS_OK;
}
SPIFFS_CHECK_RES(res);
if (fs->free_blocks < 2) {
return SPIFFS_ERR_FULL;
@ -701,7 +706,7 @@ s32_t spiffs_object_create(
// find free entry
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("create: found free page @ %04x bix:%d entry:%d\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
// occupy page in object lookup
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
@ -806,7 +811,7 @@ void spiffs_cb_object_event(
if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
if (spix == 0) {
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
SPIFFS_DBG(" callback: setting fd %d:%04x objix_hdr_pix to %04x, size:%d\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
cur_fd->objix_hdr_pix = new_pix;
if (new_size != 0) {
cur_fd->size = new_size;
@ -818,7 +823,7 @@ void spiffs_cb_object_event(
}
if (cur_fd->cursor_objix_spix == spix) {
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
SPIFFS_DBG(" callback: setting fd %d:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
cur_fd->cursor_objix_pix = new_pix;
} else {
cur_fd->cursor_objix_pix = 0;
@ -878,7 +883,7 @@ s32_t spiffs_object_open_by_page(
SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
SPIFFS_DBG("open: fd %d is obj id %04x\n", fd->file_nbr, fd->obj_id);
SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id);
return res;
}
@ -890,7 +895,7 @@ 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;
SPIFFS_DBG("append: %d bytes @ offs %d of size %d\n", len, offset, fd->size);
SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
if (offset > fd->size) {
SPIFFS_DBG("append: offset reversed to size\n");
@ -899,7 +904,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
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_DBG("append: gc check fail %i\n", res);
}
SPIFFS_CHECK_RES(res);
@ -927,7 +932,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// within this clause we return directly if something fails, object index mess-up
if (written > 0) {
// store previous object index page, unless first pass
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id,
cur_objix_pix, prev_objix_spix, written);
if (prev_objix_spix == 0) {
// this is an update to object index header page
@ -944,7 +949,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
new_objix_hdr_page, 0, written);
}
} else {
@ -960,7 +965,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("append: %04x store new size I %d in objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
offset+written, new_objix_hdr_page, 0, written);
}
fd->size = offset+written;
@ -987,9 +992,9 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
// quick "load" of new object index page
c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
c_memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %d\n", fd->obj_id
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id
, cur_objix_pix, cur_objix_spix, written);
} else {
// on first pass, we load existing object index page
@ -1001,7 +1006,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 [fd size %d]\n", fd->obj_id, pix, fd->size);
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\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);
@ -1025,7 +1030,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
&p_hdr, &data[written], to_write, page_offs, 1, &data_page);
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id,
data_page, data_spix, page_offs, to_write, written);
} else {
// append to existing page, fill out free data in existing page
@ -1042,7 +1047,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id
, data_page, data_spix, page_offs, to_write, written);
}
@ -1078,7 +1083,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
if (cur_objix_spix != 0) {
// wrote beyond object index header page
// write last modified object index page, unless object header index page
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id,
cur_objix_pix, cur_objix_spix, written);
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
@ -1092,7 +1097,7 @@ 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, res %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
, offset+written, new_objix_hdr_page, 0, written, res2);
SPIFFS_CHECK_RES(res2);
} else {
@ -1100,7 +1105,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
if (offset == 0) {
// wrote to empty object - simply update size and write whole page
objix_hdr->size = offset+written;
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
, cur_objix_pix, cur_objix_spix, written);
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
@ -1115,7 +1120,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// modifying object index header page, update size and make new copy
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
, new_objix_hdr_page, 0, written);
SPIFFS_CHECK_RES(res2);
}
@ -1163,7 +1168,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// store previous object index header page
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
SPIFFS_CHECK_RES(res);
} else {
// store new version of previous object index page
@ -1173,7 +1178,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
SPIFFS_CHECK_RES(res);
res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %d\n", new_objix_pix, objix->p_hdr.span_ix, written);
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
}
@ -1228,7 +1233,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// a full page, allocate and write a new page of data
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
&p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%d, len %d, written %d\n", data_pix, data_spix, page_offs, to_write, written);
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written);
} else {
// write to existing page, allocate new and copy unmodified data
@ -1269,7 +1274,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
(u8_t *)&p_hdr.flags);
if (res != SPIFFS_OK) break;
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%d, len %d, written %d\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
}
// delete original data page
@ -1308,7 +1313,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
SPIFFS_CHECK_RES(res2);
res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %d\n", new_objix_pix, cur_objix_spix, written);
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written);
fd->cursor_objix_pix = new_objix_pix;
fd->cursor_objix_spix = cur_objix_spix;
SPIFFS_CHECK_RES(res2);
@ -1318,7 +1323,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// wrote within object index header page
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
SPIFFS_CHECK_RES(res2);
}
@ -1438,7 +1443,7 @@ s32_t spiffs_object_truncate(
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
if (prev_objix_spix > 0) {
// update object index header page
SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %d\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix);
SPIFFS_CHECK_RES(res);
@ -1481,14 +1486,14 @@ s32_t spiffs_object_truncate(
// delete full data page
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
SPIFFS_DBG("truncate: err validating data pix %d\n", res);
SPIFFS_DBG("truncate: err validating data pix %i\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);
SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
break;
}
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
@ -1503,13 +1508,13 @@ s32_t spiffs_object_truncate(
}
fd->size = cur_size;
fd->offset = cur_size;
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%d\n", data_pix, data_spix, cur_size);
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size);
} else {
// delete last page, partially
spiffs_page_header p_hdr;
spiffs_page_ix new_data_pix;
u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
SPIFFS_DBG("truncate: delete %d bytes from data page %04x for data spix:%04x, cur_size:%d\n", bytes_to_remove, data_pix, data_spix, cur_size);
SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size);
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
if (res != SPIFFS_OK) break;
@ -1572,7 +1577,7 @@ s32_t spiffs_object_truncate(
} else {
// make uninitialized object
SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix);
c_memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
@ -1664,7 +1669,7 @@ s32_t spiffs_object_read(
len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
// remaining data in file
len_to_read = MIN(len_to_read, fd->size);
SPIFFS_DBG("read: offset:%d rd:%d data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
if (len_to_read <= 0) {
res = SPIFFS_ERR_END_OF_OBJECT;
@ -1750,7 +1755,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id
if (id >= state->min_obj_id && id <= state->max_obj_id) {
u8_t *map = (u8_t *)fs->work;
int ix = (id - state->min_obj_id) / state->compaction;
//SPIFFS_DBG("free_obj_id: add ix %d for id %04x min:%04x max%04x comp:%d\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
//SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
map[ix]++;
}
}
@ -1780,7 +1785,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
u32_t i, j;
SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id);
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id,
conflicting_name, 0, 0);
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
@ -1823,7 +1828,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
return SPIFFS_ERR_FULL;
}
SPIFFS_DBG("free_obj_id: COMP select index:%d min_count:%d min:%04x max:%04x compact:%d\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
if (min_count == 0) {
// no id in this range, skip compacting and use directly
@ -1843,9 +1848,9 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
// in a work memory of log_page_size bytes, we may fit in log_page_size ids
// todo what if compaction is > 255 - then we cannot fit it in a byte
state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%d\n", state.min_obj_id, state.max_obj_id, state.compaction);
SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction);
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0);
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
SPIFFS_CHECK_RES(res);

View File

@ -124,7 +124,7 @@
#define SPIFFS_EV_IX_NEW 1
#define SPIFFS_EV_IX_DEL 2
#define SPIFFS_OBJ_ID_IX_FLAG (1<<(8*sizeof(spiffs_obj_id)-1))
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
@ -311,6 +311,26 @@
// stop searching at end of all look up pages
#define SPIFFS_VIS_NO_WRAP (1<<2)
#if SPIFFS_HAL_CALLBACK_EXTRA
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
#else // SPIFFS_HAL_CALLBACK_EXTRA
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
(_fs)->cfg.hal_erase_f((_paddr), (_len))
#endif // SPIFFS_HAL_CALLBACK_EXTRA
#if SPIFFS_CACHE
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
@ -423,7 +443,7 @@ typedef struct __attribute(( packed ))
// common page header
spiffs_page_header p_hdr;
// alignment
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
// size of object
u32_t size;
// type of object
@ -435,7 +455,7 @@ typedef struct __attribute(( packed ))
// object index page header
typedef struct __attribute(( packed )) {
spiffs_page_header p_hdr;
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
} spiffs_page_object_ix;
// callback func for object lookup visitor
@ -665,7 +685,7 @@ s32_t spiffs_gc_clean(
spiffs_block_ix bix);
s32_t spiffs_gc_quick(
spiffs *fs);
spiffs *fs, u16_t max_free_pages);
// ---------------

View File

@ -23,9 +23,12 @@
*/
#include "FS.h"
#undef max
#undef min
#include "FSImpl.h"
#include "spiffs/spiffs.h"
#include "debug.h"
#include <limits>
extern "C" {
#include "c_types.h"
@ -119,6 +122,27 @@ protected:
config.log_block_size = _blockSize;
config.log_page_size = _pageSize;
if (((uint32_t) std::numeric_limits<spiffs_block_ix>::max()) < (_size / _blockSize)) {
DEBUGV("spiffs_block_ix type too small");
abort();
}
if (((uint32_t) std::numeric_limits<spiffs_page_ix>::max()) < (_size / _pageSize)) {
DEBUGV("spiffs_page_ix type too small");
abort();
}
if (((uint32_t) std::numeric_limits<spiffs_obj_id>::max()) < (2 + (_size / (2*_pageSize))*2)) {
DEBUGV("spiffs_obj_id type too small");
abort();
}
if (((uint32_t) std::numeric_limits<spiffs_span_ix>::max()) < (_size / _pageSize - 1)) {
DEBUGV("spiffs_span_ix type too small");
abort();
}
// hack: even though fs is not initialized at this point,
// SPIFFS_buffer_bytes_for_cache uses only fs->config.log_page_size
// suggestion: change SPIFFS_buffer_bytes_for_cache to take
@ -239,7 +263,7 @@ public:
size_t position() const override {
CHECKFD();
auto result = SPIFFS_tell(_fs->getFs(), _fd);
auto result = SPIFFS_lseek(_fs->getFs(), _fd, 0, SPIFFS_SEEK_CUR);
if (result < 0) {
DEBUGV("SPIFFS_tell rc=%d\r\n", result);
return 0;
@ -308,6 +332,13 @@ public:
return (const char*) _dirent.name;
}
size_t fileSize() override {
if (!_valid)
return 0;
return _dirent.size;
}
bool next() override {
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
_valid = (result != nullptr);
@ -374,8 +405,8 @@ extern "C" uint32_t _SPIFFS_page;
extern "C" uint32_t _SPIFFS_block;
static SPIFFSImpl s_defaultFs(
(uint32_t) &_SPIFFS_start - 0x40200000,
(uint32_t) (&_SPIFFS_end - &_SPIFFS_start),
(uint32_t) (&_SPIFFS_start) - 0x40200000,
(uint32_t) (&_SPIFFS_end) - (uint32_t) (&_SPIFFS_start),
(uint32_t) &_SPIFFS_page,
(uint32_t) &_SPIFFS_block,
5);

View File

@ -23,30 +23,11 @@
#include <algorithm>
#include "spiffs/spiffs.h"
#include "debug.h"
#include "interrupts.h"
extern "C" {
#include "c_types.h"
#include "spi_flash.h"
}
static int spi_flash_read_locked(uint32_t addr, uint32_t* dst, uint32_t size) {
InterruptLock lock;
return spi_flash_read(addr, dst, size);
}
static int spi_flash_write_locked(uint32_t addr, const uint32_t* src, uint32_t size) {
InterruptLock lock;
return spi_flash_write(addr, (uint32_t*) src, size);
}
static int spi_flash_erase_sector_locked(uint32_t sector) {
optimistic_yield(10000);
InterruptLock lock;
return spi_flash_erase_sector(sector);
}
/*
spi_flash_read function requires flash address to be aligned on word boundary.
We take care of this by reading first and last words separately and memcpy
@ -62,6 +43,8 @@ alignedEnd: ^
*/
int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
optimistic_yield(10000);
uint32_t result = SPIFFS_OK;
uint32_t alignedBegin = (addr + 3) & (~3);
uint32_t alignedEnd = (addr + size) & (~3);
@ -69,7 +52,7 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
if (addr < alignedBegin) {
uint32_t nb = alignedBegin - addr;
uint32_t tmp;
if (spi_flash_read_locked(alignedBegin - 4, &tmp, 4) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashRead(alignedBegin - 4, &tmp, 4)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -78,8 +61,8 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
}
if (alignedEnd != alignedBegin) {
if (spi_flash_read_locked(alignedBegin, (uint32_t*) (dst + alignedBegin - addr),
alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashRead(alignedBegin, (uint32_t*) (dst + alignedBegin - addr),
alignedEnd - alignedBegin)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -89,7 +72,7 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
if (addr + size > alignedEnd) {
uint32_t nb = addr + size - alignedEnd;
uint32_t tmp;
if (spi_flash_read_locked(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashRead(alignedEnd, &tmp, 4)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -114,6 +97,8 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512;
int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
optimistic_yield(10000);
uint32_t alignedBegin = (addr + 3) & (~3);
uint32_t alignedEnd = (addr + size) & (~3);
@ -121,7 +106,7 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
uint32_t nb = alignedBegin - addr;
uint32_t tmp = 0xffffffff;
memcpy(((uint8_t* )&tmp) + 4 - nb, src, nb);
if (spi_flash_write_locked(alignedBegin - 4, &tmp, 4) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashWrite(alignedBegin - 4, &tmp, 4)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -132,8 +117,8 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr);
uint32_t srcAlign = ((uint32_t) srcLeftover) & 3;
if (!srcAlign) {
if (spi_flash_write_locked(alignedBegin, (uint32_t*) srcLeftover,
alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashWrite(alignedBegin, (uint32_t*) srcLeftover,
alignedEnd - alignedBegin)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -145,8 +130,7 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
size_t willCopy = std::min(sizeLeft, sizeof(buf));
memcpy(buf, srcLeftover, willCopy);
if (spi_flash_write_locked(alignedBegin, (uint32_t*) buf,
willCopy) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashWrite(alignedBegin, (uint32_t*) buf, willCopy)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -164,7 +148,7 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
uint32_t tmp = 0xffffffff;
memcpy(&tmp, src + size - nb, nb);
if (spi_flash_write_locked(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) {
if (!ESP.flashWrite(alignedEnd, &tmp, 4)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
@ -183,7 +167,8 @@ int32_t spiffs_hal_erase(uint32_t addr, uint32_t size) {
const uint32_t sector = addr / SPI_FLASH_SEC_SIZE;
const uint32_t sectorCount = size / SPI_FLASH_SEC_SIZE;
for (uint32_t i = 0; i < sectorCount; ++i) {
if (spi_flash_erase_sector_locked(sector + i) != 0) {
optimistic_yield(10000);
if (!ESP.flashEraseSector(sector + i)) {
DEBUGV("_spif_erase addr=%x size=%d i=%d\r\n", addr, size, i);
return SPIFFS_ERR_INTERNAL;
}

View File

@ -95,22 +95,18 @@ In order to use these modules, make sure to observe the following:
### Serial Adapter
There are many different USB to Serial adapters / boards.
To be able to put ESP8266 into bootloader mode using serial handshaking lines, you need the adapter which breaks out RTS and DTR outputs. CTS and DSR are not useful for upload (they are inputs). Make sure the adapter can work with 3.3V IO voltage: it should have a jumper or a switch to select between 5V and 3.3V, or be marked as 3.3V only.
* Note
- for full upload management you need RTS and DTR
- the chip need to have 3.3V TTL (5V may damage the chip)
- not all board have all pins of the ICs as breakout (check before order)
- CTS and DSR are not useful for upload (they are Inputs)
Adapters based around the following ICs should work:
* Working ICs
- FT232RL
- CP2102
- CH340G
- maybe others (drop a comment)
PL2303-based adapters are known not to work on Mac OS X. See https://github.com/igrr/esptool-ck/issues/9 for more info.
### Minimal Hardware Setup for Bootloading and Usage
ESPxx Hardware
| PIN | Resistor | Serial Adapter |
| ------------- | -------- | -------------- |
@ -125,12 +121,12 @@ ESPxx Hardware
* Note
- GPIO15 is also named MTDO
- Reset is also named RSBT or REST (adding PullUp improves the stability of the Module)
- Reset is also named RSBT or REST (adding PullUp improves the stability of the module)
- GPIO2 is alternative TX for the boot loader mode
- **Directly connecting a pin to VCC or GND is not a substitute for a PullUp or PullDown resistor, doing this can break upload management and the serial console, instability has also been noted in some cases.**
### ESP to Serial
![ESP to Serial](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_to_serial.png)
![ESP to Serial](https://raw.githubusercontent.com/esp8266/Arduino/esp8266/docs/ESP_to_serial.png)
#### Minimal Hardware Setup for Bootloading only ##
ESPxx Hardware

View File

@ -6,18 +6,30 @@ title: Change log
### Core
- Add first batch of file system APIs
- Add file system APIs and documentation
- Add ConfigFile example
- Allow user to run code in user_rf_pre_init
- Add strtoul and strtol, fix strtod
- Update documentation for NodeMCU and Olimex boards
- Disable interrupts inside ESP.getVcc (#567)
- Erase RTC RAM only if RF mode looks invalid (#619)
### Libraries
- ESP8266WebServer: support for sending of PROGMEM strings
- ESP8266WebServer: support for serving files from file system
- ESP8266WiFi: fix mode selection (#529)
- ESP8266mDNS: allow to work on SoftAP interface
- EEPROM: round requested size to 4 bytes (#659)
- Add ESP8266AVRISP library
### Tools
- Update SDK to 1.2.0_15_07_13_p4
- Update SDK to 1.3.0_15_08_10_p1
- Update esptool to 0.4.6
- Bump toolchain version to force libm update on Windows
- ESP8266FS tool update
---
## 1.6.5-947-g39819f0

BIN
doc/esp12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -11,7 +11,7 @@ Pin 16 can be `INPUT`, `OUTPUT` or `INPUT_PULLDOWN_16`. At startup, pins are con
Pins may also serve other functions, like Serial, I2C, SPI. These functions are normally activated by the corresponding library. The diagram below shows pin mapping for the popular ESP-12 module.
![Pin Functions](https://cdn.rawgit.com/esp8266/Arduino/doc-update/hardware/esp8266com/esp8266/doc/esp12.svg)
![Pin Functions](esp12.png)
Digital pins 6—11 are not shown on this diagram because they are used to connect flash memory chip on most modules. Trying to use these pins as IOs will likely cause the program to crash.

View File

@ -0,0 +1,135 @@
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <ESP8266mDNS.h>
#include <EEPROM.h>
/*
* This example serves a "hello world" on a WLAN and a SoftAP at the same time.
* The SoftAP allow you to configure WLAN parameters at run time. They are not setup in the sketch but saved on EEPROM.
*
* Connect your computer or cell phone to wifi network ESP_ap with password 12345678. A popup may appear and it allow you to go to WLAN config. If it does not then navigate to http://192.168.4.1/wifi and config it there.
* Then wait for the module to connect to your wifi and take note of the WLAN IP it got. Then you can disconnect from ESP_ap and return to your regular WLAN.
*
* Now the ESP8266 is in your network. You can reach it through http://192.168.x.x/ (the IP you took note of) or maybe at http://esp8266.local too.
*
* This is a captive portal because through the softAP it will redirect any http request to http://192.168.4.1/
*/
/* Set these to your desired softAP credentials. They are not configurable at runtime */
const char *softAP_ssid = "ESP_ap";
const char *softAP_password = "12345678";
/* hostname for mDNS. Should work at least on windows. Try http://esp8266.local */
const char *myHostname = "esp8266";
/* Don't set this wifi credentials. They are configurated at runtime and stored on EEPROM */
char ssid[32] = "";
char password[32] = "";
// DNS server
const byte DNS_PORT = 53;
DNSServer dnsServer;
// Web server
ESP8266WebServer server(80);
/* Soft AP network parameters */
IPAddress apIP(192, 168, 4, 1);
IPAddress netMsk(255, 255, 255, 0);
/** Should I connect to WLAN asap? */
boolean connect;
/** Last time I tried to connect to WLAN */
long lastConnectTry = 0;
/** Current WLAN status */
int status = WL_IDLE_STATUS;
void setup() {
delay(1000);
Serial.begin(9600);
Serial.println();
Serial.print("Configuring access point...");
/* You can remove the password parameter if you want the AP to be open. */
WiFi.softAPConfig(apIP, apIP, netMsk);
WiFi.softAP(softAP_ssid, softAP_password);
delay(500); // Without delay I've seen the IP address blank
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP());
/* Setup the DNS server redirecting all the domains to the apIP */
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", apIP);
/* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */
server.on("/", handleRoot);
server.on("/wifi", handleWifi);
server.on("/wifisave", handleWifiSave);
server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
server.onNotFound ( handleNotFound );
server.begin(); // Web server start
Serial.println("HTTP server started");
loadCredentials(); // Load WLAN credentials from network
connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID
}
void connectWifi() {
Serial.println("Connecting as wifi client...");
WiFi.disconnect();
WiFi.begin ( ssid, password );
int connRes = WiFi.waitForConnectResult();
Serial.print ( "connRes: " );
Serial.println ( connRes );
}
void loop() {
if (connect) {
Serial.println ( "Connect requested" );
connect = false;
connectWifi();
lastConnectTry = millis();
}
{
int s = WiFi.status();
if (s == 0 && millis() > (lastConnectTry + 60000) ) {
/* If WLAN disconnected and idle try to connect */
/* Don't set retry time too low as retry interfere the softAP operation */
connect = true;
}
if (status != s) { // WLAN status change
Serial.print ( "Status: " );
Serial.println ( s );
status = s;
if (s == WL_CONNECTED) {
/* Just connected to WLAN */
Serial.println ( "" );
Serial.print ( "Connected to " );
Serial.println ( ssid );
Serial.print ( "IP address: " );
Serial.println ( WiFi.localIP() );
// Setup MDNS responder
if (!MDNS.begin(myHostname)) {
Serial.println("Error setting up MDNS responder!");
} else {
Serial.println("mDNS responder started");
// Add service to MDNS-SD
MDNS.addService("http", "tcp", 80);
}
} else if (s == WL_NO_SSID_AVAIL) {
WiFi.disconnect();
}
}
}
// Do work:
//DNS
dnsServer.processNextRequest();
//HTTP
server.handleClient();
}

View File

@ -0,0 +1,27 @@
/** Load WLAN credentials from EEPROM */
void loadCredentials() {
EEPROM.begin(512);
EEPROM.get(0, ssid);
EEPROM.get(0+sizeof(ssid), password);
char ok[2+1];
EEPROM.get(0+sizeof(ssid)+sizeof(password), ok);
EEPROM.end();
if (String(ok) != String("OK")) {
ssid[0] = 0;
password[0] = 0;
}
Serial.println("Recovered credentials:");
Serial.println(ssid);
Serial.println(strlen(password)>0?"********":"<no password>");
}
/** Store WLAN credentials to EEPROM */
void saveCredentials() {
EEPROM.begin(512);
EEPROM.put(0, ssid);
EEPROM.put(0+sizeof(ssid), password);
char ok[2+1] = "OK";
EEPROM.put(0+sizeof(ssid)+sizeof(password), ok);
EEPROM.commit();
EEPROM.end();
}

View File

@ -0,0 +1,129 @@
/** Handle root or redirect to captive portal */
void handleRoot() {
if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
return;
}
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.sendContent(
"<html><head></head><body>"
"<h1>HELLO WORLD!!</h1>"
);
if (server.client().localIP() == apIP) {
server.sendContent(String("<p>You are connected through the soft AP: ") + softAP_ssid + "</p>");
} else {
server.sendContent(String("<p>You are connected through the wifi network: ") + ssid + "</p>");
}
server.sendContent(
"<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
"</body></html>"
);
server.client().stop(); // Stop is needed because we sent no content length
}
/** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
boolean captivePortal() {
if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname)+".local")) {
Serial.print("Request redirected to captive portal");
server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true);
server.send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.client().stop(); // Stop is needed because we sent no content length
return true;
}
return false;
}
/** Wifi config page handler */
void handleWifi() {
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.sendContent(
"<html><head></head><body>"
"<h1>Wifi config</h1>"
);
if (server.client().localIP() == apIP) {
server.sendContent(String("<p>You are connected through the soft AP: ") + softAP_ssid + "</p>");
} else {
server.sendContent(String("<p>You are connected through the wifi network: ") + ssid + "</p>");
}
server.sendContent(
"\r\n<br />"
"<table><tr><th align='left'>SoftAP config</th></tr>"
);
server.sendContent(String() + "<tr><td>SSID " + String(softAP_ssid) + "</td></tr>");
server.sendContent(String() + "<tr><td>IP " + toStringIp(WiFi.softAPIP()) + "</td></tr>");
server.sendContent(
"</table>"
"\r\n<br />"
"<table><tr><th align='left'>WLAN config</th></tr>"
);
server.sendContent(String() + "<tr><td>SSID " + String(ssid) + "</td></tr>");
server.sendContent(String() + "<tr><td>IP " + toStringIp(WiFi.localIP()) + "</td></tr>");
server.sendContent(
"</table>"
"\r\n<br />"
"<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>"
);
Serial.println("scan start");
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n > 0) {
for (int i = 0; i < n; i++) {
server.sendContent(String() + "\r\n<tr><td>SSID " + String(WiFi.SSID(i)) + String((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":" *") + " (" + WiFi.RSSI(i) + ")</td></tr>");
}
} else {
server.sendContent(String() + "<tr><td>No WLAN found</td></tr>");
}
server.sendContent(
"</table>"
"\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>"
"<input type='text' placeholder='network' name='n'/>"
"<br /><input type='password' placeholder='password' name='p'/>"
"<br /><input type='submit' value='Connect/Disconnect'/></form>"
"<p>You may want to <a href='/'>return to the home page</a>.</p>"
"</body></html>"
);
server.client().stop(); // Stop is needed because we sent no content length
}
/** Handle the WLAN save form and redirect to WLAN config page again */
void handleWifiSave() {
Serial.println("wifi save");
server.arg("n").toCharArray(ssid, sizeof(ssid) - 1);
server.arg("p").toCharArray(password, sizeof(password) - 1);
server.sendHeader("Location", "wifi", true);
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.client().stop(); // Stop is needed because we sent no content length
saveCredentials();
connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID
}
void handleNotFound() {
if (captivePortal()) { // If caprive portal redirect instead of displaying the error page.
return;
}
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.send ( 404, "text/plain", message );
}

View File

@ -0,0 +1,21 @@
/** Is this an IP? */
boolean isIp(String str) {
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
/** IP to String? */
String toStringIp(IPAddress ip) {
String res = "";
for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF);
return res;
}

View File

@ -2,6 +2,9 @@
#include <lwip/def.h>
#include <Arduino.h>
#define DEBUG
#define DEBUG_OUTPUT Serial
DNSServer::DNSServer()
{
_ttl = htonl(60);
@ -110,16 +113,43 @@ void DNSServer::replyWithIP()
{
_dnsHeader->QR = DNS_QR_RESPONSE;
_dnsHeader->ANCount = _dnsHeader->QDCount;
_dnsHeader->QDCount = 0;
_dnsHeader->QDCount = _dnsHeader->QDCount;
//_dnsHeader->RA = 1;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write(_buffer, _currentPacketSize);
_udp.write((uint8_t)192); // answer name is a pointer
_udp.write((uint8_t)12); // pointer to offset at 0x00c
_udp.write((uint8_t)0); // 0x0001 answer is type A query (host address)
_udp.write((uint8_t)1);
_udp.write((uint8_t)0); //0x0001 answer is class IN (internet address)
_udp.write((uint8_t)1);
_udp.write((unsigned char*)&_ttl, 4);
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
_udp.write((uint8_t)0);
_udp.write((uint8_t)4);
_udp.write(_resolvedIP, sizeof(_resolvedIP));
_udp.endPacket();
#ifdef DEBUG
DEBUG_OUTPUT.print("DNS responds: ");
DEBUG_OUTPUT.print(_resolvedIP[0]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[1]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[2]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[3]);
DEBUG_OUTPUT.print(" for ");
DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix());
#endif
}
void DNSServer::replyWithCustomCode()

View File

@ -24,8 +24,8 @@
#include <Arduino.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "FS.h"
#include "ESP8266WebServer.h"
#include "FS.h"
#include "detail/RequestHandler.h"
// #define DEBUG
#define DEBUG_OUTPUT Serial
@ -253,6 +253,10 @@ bool ESP8266WebServer::hasArg(const char* name) {
return false;
}
String ESP8266WebServer::hostHeader() {
return _hostHeader;
}
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
_fileUploadHandler = fn;
}

View File

@ -38,7 +38,10 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
class RequestHandler;
namespace fs {
class FS;
}
typedef struct {
HTTPUploadStatus status;
@ -62,7 +65,7 @@ public:
typedef std::function<void(void)> THandlerFunction;
void on(const char* uri, THandlerFunction handler);
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
void serveStatic(const char* uri, FS& fs, const char* path);
void serveStatic(const char* uri, fs::FS& fs, const char* path);
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads
@ -77,6 +80,8 @@ public:
int args(); // get arguments count
bool hasArg(const char* name); // check if argument exists
String hostHeader(); // get request host header if available or empty String if not
// send response to the client
// code - HTTP response code, can be 200 or 404
// content_type - HTTP content type, like "text/plain" or "image/png"
@ -108,7 +113,7 @@ protected:
bool _parseRequest(WiFiClient& client);
void _parseArguments(String data);
static const char* _responseCodeToString(int code);
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(WiFiClient& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
@ -131,6 +136,8 @@ protected:
size_t _contentLength;
String _responseHeaders;
String _hostHeader;
RequestHandler* _firstHandler;
RequestHandler* _lastHandler;
THandlerFunction _notFoundHandler;

View File

@ -24,8 +24,8 @@
#include "WiFiClient.h"
#include "ESP8266WebServer.h"
// #define DEBUG
#define DEBUG_OUTPUT Serial1
#define DEBUG
#define DEBUG_OUTPUT Serial
bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
// Read the first line of HTTP request
@ -94,6 +94,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 2);
#ifdef DEBUG
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName == "Content-Type"){
if (headerValue.startsWith("text/plain")){
isForm = false;
@ -103,6 +111,8 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
}
} else if (headerName == "Content-Length"){
contentLength = headerValue.toInt();
} else if (headerName == "Host"){
_hostHeader = headerValue;
}
}
@ -131,9 +141,36 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
}
_parseArguments(searchStr);
if (isForm){
_parseForm(client, boundaryStr, contentLength);
if (!_parseForm(client, boundaryStr, contentLength)) {
return false;
}
}
} else {
String headerName;
String headerValue;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 2);
#ifdef DEBUG
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName == "Host"){
_hostHeader = headerValue;
}
}
_parseArguments(searchStr);
}
client.flush();
@ -242,7 +279,7 @@ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
return (uint8_t)res;
}
void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
#ifdef DEBUG
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
@ -251,7 +288,12 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
DEBUG_OUTPUT.println(len);
#endif
String line;
line = client.readStringUntil('\r');
int retry = 0;
do {
line = client.readStringUntil('\r');
++retry;
} while (line.length() == 0 && retry < 3);
client.readStringUntil('\n');
//start reading the form
if (line == ("--"+boundary)){
@ -429,7 +471,11 @@ readfile:
}
_currentArgCount = iarg;
if (postArgs) delete[] postArgs;
return true;
}
#ifdef DEBUG
DEBUG_OUTPUT.print("Error: line: ");
DEBUG_OUTPUT.println(line);
#endif
return false;
}

View File

@ -263,6 +263,22 @@ uint16_t WiFiClient::remotePort()
return _client->getRemotePort();
}
IPAddress WiFiClient::localIP()
{
if (!_client)
return IPAddress(0U);
return IPAddress(_client->getLocalAddress());
}
uint16_t WiFiClient::localPort()
{
if (!_client)
return 0;
return _client->getLocalPort();
}
int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err)
{
return reinterpret_cast<WiFiClient*>(arg)->_connected(tpcb, err);

View File

@ -60,6 +60,8 @@ public:
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
bool getNoDelay();
void setNoDelay(bool nodelay);
static void setLocalPortStart(uint16_t port) { _localPort = port; }

View File

@ -125,6 +125,12 @@ class ClientContext {
return _pcb->remote_port;
}
uint32_t getLocalAddress() {
if(!_pcb) return 0;
return _pcb->local_ip.addr;
}
uint16_t getLocalPort() {
if(!_pcb) return 0;