From 81ea8d9597e4d77a9d746e7ae48e9ecd9f77f894 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 10 Mar 2015 01:12:36 +0800 Subject: [PATCH] add math, add file.fsinfo(), update spiffs. --- .travis.yml | 2 +- README.md | 10 ++++++++ app/include/user_version.h | 2 +- app/modules/file.c | 17 +++++++++++++ app/spiffs/spiffs.c | 2 +- app/spiffs/spiffs.h | 35 ++++++++++++++++++++++++--- app/spiffs/spiffs_config.h | 10 ++++---- app/spiffs/spiffs_gc.c | 24 +++++++++++------- app/spiffs/spiffs_hydrogen.c | 47 +++++++++++++++++++++++++++++------- app/spiffs/spiffs_nucleus.c | 21 ++++++++++------ app/spiffs/spiffs_nucleus.h | 6 ++--- examples/fragment.lua | 7 ++++++ 12 files changed, 144 insertions(+), 39 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45aedeab..e3ae24df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: script: - make all - cd bin/ -- file_name="nodemcu-firmware_v${TRAVIS_TAG}.${TRAVIS_BUILD_NUMBER}.bin" +- file_name="nodemcu_${TRAVIS_TAG}.bin" - srec_cat -output ${file_name} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000 deploy: provider: releases diff --git a/README.md b/README.md index 43980e13..89fa0480 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ Tencent QQ group: 309957875
- Build-in file, timer, pwm, i2c, spi, 1-wire, net, mqtt, coap, gpio, wifi, adc, uart and system api. - GPIO pin re-mapped, use the index to access gpio, i2c, pwm. +# Downloads +[releases](https://github.com/nodemcu/nodemcu-firmware/releases) + # To Do List (pull requests are very welcomed) - loadable c module - fix wifi smart connect @@ -33,6 +36,13 @@ Tencent QQ group: 309957875
- cross compiler (done) # Change log +2015-03-10
+update to the recent spiffs.
+add file.fsinfo() api, usage: remain, used, total = file.fsinfo().
+add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).
+add math lib, partial api work.
+u8g module, ws2812 module default enabled in dev-branch build. + 2015-02-13
add node.compile() api to compile lua text file into lua bytecode file.
this will reduce memory usage noticeably when require modules into NodeMCU.
diff --git a/app/include/user_version.h b/app/include/user_version.h index c1144958..4a7f5f6d 100644 --- a/app/include/user_version.h +++ b/app/include/user_version.h @@ -7,6 +7,6 @@ #define NODE_VERSION_INTERNAL 0U #define NODE_VERSION "NodeMCU 0.9.5" -#define BUILD_DATE "build 20150306" +#define BUILD_DATE "build 20150310" #endif /* __USER_VERSION_H__ */ diff --git a/app/modules/file.c b/app/modules/file.c index cf10a3a7..117ea128 100644 --- a/app/modules/file.c +++ b/app/modules/file.c @@ -175,6 +175,22 @@ static int file_rename( lua_State* L ) return 1; } +// Lua: fsinfo() +static int file_fsinfo( lua_State* L ) +{ + uint32_t total, used; + SPIFFS_info(&fs, &total, &used); + NODE_DBG("total: %d, used:%d\n", total, used); + if(total>0x7FFFFFFF || used>0x7FFFFFFF || used > total) + { + return luaL_error(L, "file system error");; + } + lua_pushinteger(L, total-used); + lua_pushinteger(L, used); + lua_pushinteger(L, total); + return 3; +} + #endif // g_read() @@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] = { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) }, // { LSTRKEY( "check" ), LFUNCVAL( file_check ) }, { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) }, + { LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) }, #endif #if LUA_OPTIMIZE_MEMORY > 0 diff --git a/app/spiffs/spiffs.c b/app/spiffs/spiffs.c index df749e09..e96e15a0 100644 --- a/app/spiffs/spiffs.c +++ b/app/spiffs/spiffs.c @@ -160,7 +160,7 @@ int myspiffs_error( int fd ){ return SPIFFS_errno(&fs); } void myspiffs_clearerr( int fd ){ - fs.errno = SPIFFS_OK; + SPIFFS_clearerr(&fs); } int myspiffs_rename( const char *old, const char *newname ){ return SPIFFS_rename(&fs, (char *)old, (char *)newname); diff --git a/app/spiffs/spiffs.h b/app/spiffs/spiffs.h index 23228446..c5a2c1d2 100644 --- a/app/spiffs/spiffs.h +++ b/app/spiffs/spiffs.h @@ -9,6 +9,10 @@ #ifndef SPIFFS_H_ #define SPIFFS_H_ +#if defined(__cplusplus) +extern "C" { +#endif + #include "c_stdio.h" #include "spiffs_config.h" @@ -181,7 +185,7 @@ typedef struct { u32_t fd_count; // last error - s32_t errno; + s32_t err_code; // current number of free blocks u32_t free_blocks; @@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh); * Renames a file * @param fs the file system struct * @param old path of file to rename - * @param new new path of file + * @param newPath new path of file */ -s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); +s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath); /** * Returns last error of last file operation. @@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); */ s32_t SPIFFS_errno(spiffs *fs); +/** + * Clears last error. + * @param fs the file system struct + */ +void SPIFFS_clearerr(spiffs *fs); + /** * Opens a directory stream corresponding to the given name. * The stream is positioned at the first entry in the directory. @@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); */ s32_t SPIFFS_check(spiffs *fs); + +/** + * Returns number of total bytes available and number of used bytes. + * This is an estimation, and depends on if there a many files with little + * data or few files with much data. + * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should + * run. This indicates a power loss in midst of things. In worst case + * (repeated powerlosses in mending or gc) you might have to delete some files. + * + * @param fs the file system struct + * @param total total number of bytes in filesystem + * @param used used number of bytes in filesystem + */ +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); + /** * Check if EOF reached. * @param fs the file system struct @@ -468,4 +493,8 @@ int myspiffs_check( void ); int myspiffs_rename( const char *old, const char *newname ); size_t myspiffs_size( int fd ); +#if defined(__cplusplus) +} +#endif + #endif /* SPIFFS_H_ */ diff --git a/app/spiffs/spiffs_config.h b/app/spiffs/spiffs_config.h index 8a8fc4b3..3ed8d03d 100644 --- a/app/spiffs/spiffs_config.h +++ b/app/spiffs/spiffs_config.h @@ -30,19 +30,19 @@ typedef uint8_t u8_t; // Set generic spiffs debug output call. #ifndef SPIFFS_DGB -#define SPIFFS_DBG(...) +#define SPIFFS_DBG(...) //printf(__VA_ARGS__) #endif // Set spiffs debug output call for garbage collecting. #ifndef SPIFFS_GC_DGB -#define SPIFFS_GC_DBG(...) +#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__) #endif // Set spiffs debug output call for caching. #ifndef SPIFFS_CACHE_DGB -#define SPIFFS_CACHE_DBG(...) +#define SPIFFS_CACHE_DBG(...) //printf("CA: " __VA_ARGS__) #endif // Set spiffs debug output call for system consistency checks. #ifndef SPIFFS_CHECK_DGB -#define SPIFFS_CHECK_DBG(...) +#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) #endif // Enable/disable API functions to determine exact number of bytes @@ -77,7 +77,7 @@ typedef uint8_t u8_t; // Define maximum number of gc runs to perform to reach desired free pages. #ifndef SPIFFS_GC_MAX_RUNS -#define SPIFFS_GC_MAX_RUNS 3 +#define SPIFFS_GC_MAX_RUNS 5 #endif // Enable/disable statistics on gc. Debug/test purpose only. diff --git a/app/spiffs/spiffs_gc.c b/app/spiffs/spiffs_gc.c index 4d6c8971..22168802 100644 --- a/app/spiffs/spiffs_gc.c +++ b/app/spiffs/spiffs_gc.c @@ -119,13 +119,13 @@ s32_t spiffs_gc_check( spiffs *fs, u32_t len) { s32_t res; - u32_t free_pages = - (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count + s32_t free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2) - fs->stats_p_allocated - fs->stats_p_deleted; int tries = 0; if (fs->free_blocks > 3 && - len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) { + (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { return SPIFFS_OK; } @@ -168,16 +168,22 @@ s32_t spiffs_gc_check( SPIFFS_CHECK_RES(res); free_pages = - (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) - fs->stats_p_allocated - fs->stats_p_deleted; } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || - len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); - SPIFFS_GC_DBG("gc_check: finished\n"); + (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs))); - //printf("gcing 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); + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + res = SPIFFS_ERR_FULL; + } + + SPIFFS_GC_DBG("gc_check: finished, %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); return res; } diff --git a/app/spiffs/spiffs_hydrogen.c b/app/spiffs/spiffs_hydrogen.c index 20e45ecf..11c960b4 100644 --- a/app/spiffs/spiffs_hydrogen.c +++ b/app/spiffs/spiffs_hydrogen.c @@ -103,7 +103,11 @@ void SPIFFS_unmount(spiffs *fs) { } s32_t SPIFFS_errno(spiffs *fs) { - return fs->errno; + return fs->err_code; +} + +void SPIFFS_clearerr(spiffs *fs) { + fs->err_code = SPIFFS_OK; } s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { @@ -314,8 +318,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { #endif } - SPIFFS_DBG("SPIFFS_write %i %04x offs:%i len %i\n", fh, fd->obj_id, offset, len); - #if SPIFFS_CACHE_WR if ((fd->flags & SPIFFS_DIRECT) == 0) { if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { @@ -334,6 +336,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); } else { // writing within cache alloc_cpage = 0; @@ -580,7 +583,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); if (res < SPIFFS_OK) { - fs->errno = res; + fs->err_code = res; } spiffs_cache_fd_release(fs, fd->cache_page); } @@ -605,7 +608,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { void SPIFFS_close(spiffs *fs, spiffs_file fh) { if (!SPIFFS_CHECK_MOUNT(fs)) { - fs->errno = SPIFFS_ERR_NOT_MOUNTED; + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return; } SPIFFS_LOCK(fs); @@ -661,7 +664,7 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) { (void)name; if (!SPIFFS_CHECK_MOUNT(fs)) { - fs->errno = SPIFFS_ERR_NOT_MOUNTED; + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; } d->fs = fs; @@ -707,7 +710,7 @@ static s32_t spiffs_read_dir_v( struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { if (!SPIFFS_CHECK_MOUNT(d->fs)) { - d->fs->errno = SPIFFS_ERR_NOT_MOUNTED; + d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; } SPIFFS_LOCK(fs); @@ -732,7 +735,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { d->entry = entry + 1; ret = e; } else { - d->fs->errno = res; + d->fs->err_code = res; } SPIFFS_UNLOCK(fs); return ret; @@ -760,6 +763,29 @@ s32_t SPIFFS_check(spiffs *fs) { return res; } +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs); + u32_t blocks = fs->block_count; + u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs); + u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs); + u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page + + if (total) { + *total = total_data_pages * data_page_size; + } + + if (used) { + *used = fs->stats_p_allocated * data_page_size; + } + + SPIFFS_UNLOCK(fs); + return res; +} + s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -878,11 +904,14 @@ s32_t SPIFFS_vis(spiffs *fs) { } // per block spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count); - spiffs_printf("last_errno: %i\n", fs->errno); + 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: %i of %i\n", used, total); SPIFFS_UNLOCK(fs); return res; diff --git a/app/spiffs/spiffs_nucleus.c b/app/spiffs/spiffs_nucleus.c index 74217cd0..ea15eba4 100644 --- a/app/spiffs/spiffs_nucleus.c +++ b/app/spiffs/spiffs_nucleus.c @@ -811,7 +811,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; - res = spiffs_gc_check(fs, len); + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta SPIFFS_CHECK_RES(res); spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; @@ -912,7 +912,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); SPIFFS_CHECK_RES(res); } - SPIFFS_DBG("append: %04x found object index at page %04x\n", fd->obj_id, pix); + SPIFFS_DBG("append: %04x found object index at page %04x [fd size %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); @@ -1003,8 +1003,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // update size in object header index page res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); - SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id - , offset+written, new_objix_hdr_page, 0, written); + 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 { // wrote within object index header page @@ -1386,13 +1386,20 @@ s32_t spiffs_object_truncate( ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; } + SPIFFS_DBG("truncate: got data pix %04x\n", data_pix); + if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { // delete full data page res = spiffs_page_data_check(fs, fd, data_pix, data_spix); - if (res != SPIFFS_OK) break; + if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK) break; + + if (res == SPIFFS_OK) { + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) break; + } else if (res == SPIFFS_ERR_DELETED) { + res = SPIFFS_OK; + } - res = spiffs_page_delete(fs, data_pix); - if (res != SPIFFS_OK) break; // update current size if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) { cur_size -= SPIFFS_DATA_PAGE_SIZE(fs); diff --git a/app/spiffs/spiffs_nucleus.h b/app/spiffs/spiffs_nucleus.h index 9b10d918..b4a34bcf 100644 --- a/app/spiffs/spiffs_nucleus.h +++ b/app/spiffs/spiffs_nucleus.h @@ -247,19 +247,19 @@ #define SPIFFS_API_CHECK_MOUNT(fs) \ if (!SPIFFS_CHECK_MOUNT((fs))) { \ - (fs)->errno = SPIFFS_ERR_NOT_MOUNTED; \ + (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \ return -1; \ } #define SPIFFS_API_CHECK_RES(fs, res) \ if ((res) < SPIFFS_OK) { \ - (fs)->errno = (res); \ + (fs)->err_code = (res); \ return -1; \ } #define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ if ((res) < SPIFFS_OK) { \ - (fs)->errno = (res); \ + (fs)->err_code = (res); \ SPIFFS_UNLOCK(fs); \ return -1; \ } diff --git a/examples/fragment.lua b/examples/fragment.lua index c3b980dc..9c531281 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -363,3 +363,10 @@ cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun cc = coap.Client() cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core") cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello") + + +file.open("test1.txt", "a+") for i = 1, 100*1000 do file.write("x") end file.close() print("Done.") +for n,s in pairs(file.list()) do print(n.." size: "..s) end +file.remove("test1.txt") +for n,s in pairs(file.list()) do print(n.." size: "..s) end +file.open("test2.txt", "a+") for i = 1, 1*1000 do file.write("x") end file.close() print("Done.")