diff --git a/README.md b/README.md index b1d8ebd0..e59aef82 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # **NodeMCU** # -version 0.9.5 +version 0.9.6 [![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nodemcu/nodemcu-firmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Download](https://img.shields.io/badge/download-~400k-orange.svg)](https://github.com/nodemcu/nodemcu-firmware/releases/latest) @@ -36,6 +36,39 @@ Tencent QQ group: 309957875
- cross compiler (done) # Change log +2015-04-06
+bump version to 0.9.6. not follow sdk version any more.
+fix mqtt module bugs. please see examples [mqtt](https://github.com/nodemcu/nodemcu-firmware/tree/master/lua_examples/mqtt).
+fix dht lib.
+update spiffs to V0.3.0.
+enhancement for wifi.ap submodule.
+wifi.sta.config (wifi_station_config): +- range checking password length (8~64) + +wifi.ap.config (wifi_ap_config): +- range checking ssid length (1~32) +- range checking pwd length (8~64) +- new params: + - auth: wifi.OPEN, wifi.WPA_PSK, wifi.WPA2_PSK, wifi.WPA_WPA2_PSK + - default WITH pwd: wifi.WPA_WPA2_PSK + - default WITHOUT pwd: wifi.OPEN + - channel: 1~13 (default: 6) + - hidden: 0/1 (default: 0) + - max: 1~4 (default: 4) + - beacon: 100~60000ms (default: 100) + +wifi.ap.getclient (wifi_ap_listclient): +- returns table(mac,ip) of all connected clients + +wifi.ap.dhcp: +- new submodule +- config (wifi_ap_dhcp_config), returns start/end ips + - params: + - start (e.g., "192.168.1.100") + - end ip calculated from wifi.ap.config.max +- start (wifi_ap_dhcp_start), returns boolean +- stop (wifi_ap_dhcp_stop), returns boolean + 2015-03-31
polish mqtt module, add queue for mqtt module.
add reconnect option to mqtt.connect api, :connect( host, port, secure, auto_reconnect, function(client) )
@@ -209,44 +242,8 @@ baudrate:9600 end) ``` -####Connect to MQTT Broker - -```lua --- init mqtt client with keepalive timer 120sec -m = mqtt.Client("clientid", 120, "user", "password") - --- setup Last Will and Testament (optional) --- Broker will publish a message with qos = 0, retain = 0, data = "offline" --- to topic "/lwt" if client don't send keepalive packet -m:lwt("/lwt", "offline", 0, 0) - -m:on("connect", function(con) print ("connected") end) -m:on("offline", function(con) print ("offline") end) - --- on publish message receive event -m:on("message", function(conn, topic, data) - print(topic .. ":" ) - if data ~= nil then - print(data) - end -end) - --- m:connect( host, port, secure, auto_reconnect, function(client) ) --- for secure: m:connect("192.168.11.118", 1880, 1, 0) --- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1) -m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end) - --- subscribe topic with qos = 0 -m:subscribe("/topic",0, function(conn) print("subscribe success") end) --- or subscribe multiple topic (topic/0, qos = 0; topic/1, qos = 1; topic2 , qos = 2) --- m:subscribe({["topic/0"]=0,["topic/1"]=1,topic2=2}, function(conn) print("subscribe success") end) --- publish a message with data = hello, QoS = 0, retain = 0 -m:publish("/topic","hello",0,0, function(conn) print("sent") end) - -m:close(); -- if auto-reconnect == 1, will disable auto-reconnect and then disconnect from host. --- you can call m:connect again - -``` +#### MQTT examples +please see [mqtt examples](https://github.com/nodemcu/nodemcu-firmware/tree/master/lua_examples/mqtt) #### UDP client and server ```lua diff --git a/app/include/user_version.h b/app/include/user_version.h index e9357259..a8c4785e 100644 --- a/app/include/user_version.h +++ b/app/include/user_version.h @@ -3,10 +3,10 @@ #define NODE_VERSION_MAJOR 0U #define NODE_VERSION_MINOR 9U -#define NODE_VERSION_REVISION 5U +#define NODE_VERSION_REVISION 6U #define NODE_VERSION_INTERNAL 0U -#define NODE_VERSION "NodeMCU 0.9.5" -#define BUILD_DATE "build 20150405" +#define NODE_VERSION "NodeMCU 0.9.6" +#define BUILD_DATE "build 20150406" #endif /* __USER_VERSION_H__ */ diff --git a/app/spiffs/spiffs.c b/app/spiffs/spiffs.c index bcb11d5c..8d6914f8 100644 --- a/app/spiffs/spiffs.c +++ b/app/spiffs/spiffs.c @@ -78,17 +78,21 @@ void myspiffs_unmount() { int myspiffs_format( void ) { SPIFFS_unmount(&fs); - u32_t sect_first, sect_last; - sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL ); - sect_first += 0x3000; - sect_first &= 0xFFFFC000; // align to 4 sector. - sect_first = platform_flash_get_sector_of_address(sect_first); - sect_last = INTERNAL_FLASH_SIZE + INTERNAL_FLASH_START_ADDRESS - 4; - sect_last = platform_flash_get_sector_of_address(sect_last); - NODE_DBG("sect_first: %x, sect_last: %x\n", sect_first, sect_last); - while( sect_first <= sect_last ) - if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR ) - return 0; + // u32_t sect_first, sect_last; + // sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL ); + // sect_first += 0x3000; + // sect_first &= 0xFFFFC000; // align to 4 sector. + // sect_first = platform_flash_get_sector_of_address(sect_first); + // sect_last = INTERNAL_FLASH_SIZE + INTERNAL_FLASH_START_ADDRESS - 4; + // sect_last = platform_flash_get_sector_of_address(sect_last); + // NODE_DBG("sect_first: %x, sect_last: %x\n", sect_first, sect_last); + // while( sect_first <= sect_last ) + // if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR ) + // return 0; + int32_t res = SPIFFS_format(&fs); + if (res != SPIFFS_OK) { + return 0; + } myspiffs_mount(); return 1; } diff --git a/app/spiffs/spiffs.h b/app/spiffs/spiffs.h index 7132b92d..d018e52c 100644 --- a/app/spiffs/spiffs.h +++ b/app/spiffs/spiffs.h @@ -41,6 +41,13 @@ extern "C" { #define SPIFFS_ERR_NOT_WRITABLE -10021 #define SPIFFS_ERR_NOT_READABLE -10022 #define SPIFFS_ERR_CONFLICTING_NAME -10023 +#define SPIFFS_ERR_NOT_CONFIGURED -10024 + +#define SPIFFS_ERR_NOT_A_FS -10025 +#define SPIFFS_ERR_MOUNTED -10026 +#define SPIFFS_ERR_ERASE_FAIL -10027 +#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028 + #define SPIFFS_ERR_INTERNAL -10050 @@ -215,6 +222,11 @@ typedef struct { // check callback function spiffs_check_callback check_cb_f; + + // mounted flag + u8_t mounted; + // config magic + u32_t config_magic; } spiffs; /* spiffs file status struct */ @@ -242,7 +254,10 @@ typedef struct { // functions /** - * Initializes the file system dynamic parameters and mounts the filesystem + * Initializes the file system dynamic parameters and mounts the filesystem. + * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS + * if the flash does not contain a recognizable file system. + * In this case, SPIFFS_format must be called prior to remounting. * @param fs the file system struct * @param config the physical and logical configuration of the file system * @param work a memory work buffer comprising 2*config->log_page_size @@ -441,6 +456,24 @@ s32_t SPIFFS_check(spiffs *fs); */ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); +/** + * Formats the entire file system. All data will be lost. + * The filesystem must not be mounted when calling this. + * + * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount + * MUST be called prior to formatting in order to configure the filesystem. + * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling + * SPIFFS_format. + * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling + * SPIFFS_unmount first. + */ +s32_t SPIFFS_format(spiffs *fs); + +/** + * Returns nonzero if spiffs is mounted, or zero if unmounted. + */ +u8_t SPIFFS_mounted(spiffs *fs); + /** * Check if EOF reached. * @param fs the file system struct diff --git a/app/spiffs/spiffs_config.h b/app/spiffs/spiffs_config.h index d80e7d22..18b93af5 100644 --- a/app/spiffs/spiffs_config.h +++ b/app/spiffs/spiffs_config.h @@ -119,14 +119,22 @@ typedef uint8_t u8_t; #define SPIFFS_COPY_BUFFER_STACK (64) #endif +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + // SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level // These should be defined on a multithreaded system -// define this to entering a mutex if you're running on a multithreaded system +// define this to enter a mutex if you're running on a multithreaded system #ifndef SPIFFS_LOCK #define SPIFFS_LOCK(fs) #endif -// define this to exiting a mutex if you're running on a multithreaded system +// define this to exit a mutex if you're running on a multithreaded system #ifndef SPIFFS_UNLOCK #define SPIFFS_UNLOCK(fs) #endif @@ -159,7 +167,12 @@ typedef uint8_t u8_t; #endif #endif -// Set SPFIFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function // in the api. This function will visualize all filesystem using given printf // function. #ifndef SPIFFS_TEST_VISUALISATION diff --git a/app/spiffs/spiffs_gc.c b/app/spiffs/spiffs_gc.c index 2ad31d07..ee9ce075 100644 --- a/app/spiffs/spiffs_gc.c +++ b/app/spiffs/spiffs_gc.c @@ -8,31 +8,11 @@ static s32_t spiffs_gc_erase_block( spiffs *fs, spiffs_block_ix bix) { s32_t res; - u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); - s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); SPIFFS_GC_DBG("gc: erase block %i\n", bix); - - // here we ignore res, just try erasing the block - while (size > 0) { - SPIFFS_GC_DBG("gc: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); - (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); - addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); - size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); - } - fs->free_blocks++; - - // register erase count for this block - res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, - SPIFFS_ERASE_COUNT_PADDR(fs, bix), - sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + res = spiffs_erase_block(fs, bix); SPIFFS_CHECK_RES(res); - fs->max_erase_count++; - if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { - fs->max_erase_count = 0; - } - #if SPIFFS_CACHE { u32_t i; diff --git a/app/spiffs/spiffs_hydrogen.c b/app/spiffs/spiffs_hydrogen.c index 3ca01463..5ef0ec59 100644 --- a/app/spiffs/spiffs_hydrogen.c +++ b/app/spiffs/spiffs_hydrogen.c @@ -21,6 +21,36 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) { #endif #endif +u8_t SPIFFS_mounted(spiffs *fs) { + return SPIFFS_CHECK_MOUNT(fs); +} + +s32_t SPIFFS_format(spiffs *fs) { + SPIFFS_API_CHECK_CFG(fs); + if (SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_MOUNTED; + return -1; + } + + s32_t res; + SPIFFS_LOCK(fs); + + spiffs_block_ix bix = 0; + while (bix < fs->block_count) { + fs->max_erase_count = 0; + res = spiffs_erase_block(fs, bix); + if (res != SPIFFS_OK) { + res = SPIFFS_ERR_ERASE_FAIL; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + bix++; + } + + SPIFFS_UNLOCK(fs); + + return 0; +} + s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, u8_t *fd_space, u32_t fd_space_size, void *cache, u32_t cache_size, @@ -65,7 +95,16 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, spiffs_cache_init(fs); #endif - s32_t res = spiffs_obj_lu_scan(fs); + s32_t res; + +#if SPIFFS_USE_MAGIC + res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + fs->config_magic = SPIFFS_CONFIG_MAGIC; + + res = spiffs_obj_lu_scan(fs); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs)); @@ -79,13 +118,15 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, fs->check_cb_f = check_cb_f; + fs->mounted = 1; + SPIFFS_UNLOCK(fs); return 0; } void SPIFFS_unmount(spiffs *fs) { - if (!SPIFFS_CHECK_MOUNT(fs)) return; + if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return; SPIFFS_LOCK(fs); u32_t i; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; @@ -98,7 +139,8 @@ void SPIFFS_unmount(spiffs *fs) { spiffs_fd_return(fs, cur_fd->file_nbr); } } - fs->block_count = 0; + fs->mounted = 0; + SPIFFS_UNLOCK(fs); } @@ -112,6 +154,7 @@ void SPIFFS_clearerr(spiffs *fs) { s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { (void)mode; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); spiffs_obj_id obj_id; @@ -127,6 +170,7 @@ s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode) { (void)mode; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -185,6 +229,7 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode } spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -214,6 +259,7 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl } s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -282,6 +328,7 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs } s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -400,6 +447,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { } s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -444,6 +492,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { } s32_t SPIFFS_remove(spiffs *fs, char *path) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -477,6 +526,7 @@ s32_t SPIFFS_remove(spiffs *fs, char *path) { } s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -525,6 +575,7 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi } s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -542,6 +593,7 @@ s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) { } s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -595,6 +647,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); s32_t res = SPIFFS_OK; #if SPIFFS_CACHE_WR @@ -608,6 +661,11 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { } void SPIFFS_close(spiffs *fs, spiffs_file fh) { + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return; + } + if (!SPIFFS_CHECK_MOUNT(fs)) { fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return; @@ -623,6 +681,7 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -664,10 +723,17 @@ 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_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return 0; + } + if (!SPIFFS_CHECK_MOUNT(fs)) { fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; } + d->fs = fs; d->block = 0; d->entry = 0; @@ -743,12 +809,14 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { } s32_t SPIFFS_closedir(spiffs_DIR *d) { + SPIFFS_API_CHECK_CFG(d->fs); SPIFFS_API_CHECK_MOUNT(d->fs); return 0; } s32_t SPIFFS_check(spiffs *fs) { s32_t res; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -766,6 +834,7 @@ s32_t SPIFFS_check(spiffs *fs) { s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -847,6 +916,7 @@ s32_t SPIFFS_size(spiffs *fs, spiffs_file fh) { #if SPIFFS_TEST_VISUALISATION s32_t SPIFFS_vis(spiffs *fs) { s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); diff --git a/app/spiffs/spiffs_nucleus.c b/app/spiffs/spiffs_nucleus.c index 4ab63b23..5f15ee55 100644 --- a/app/spiffs/spiffs_nucleus.c +++ b/app/spiffs/spiffs_nucleus.c @@ -213,6 +213,45 @@ s32_t spiffs_obj_lu_find_entry_visitor( return SPIFFS_VIS_END; } +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); + s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + // here we ignore res, just try erasing the block + while (size > 0) { + SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); + size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); + } + fs->free_blocks++; + + // register erase count for this block + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_USE_MAGIC + // finally, write magic + spiffs_obj_id magic = SPIFFS_MAGIC(fs); + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_MAGIC_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&magic); + SPIFFS_CHECK_RES(res); +#endif + + fs->max_erase_count++; + if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { + fs->max_erase_count = 0; + } + + return res; +} + static s32_t spiffs_obj_lu_scan_v( spiffs *fs, @@ -238,40 +277,44 @@ static s32_t spiffs_obj_lu_scan_v( return SPIFFS_VIS_COUNTINUE; } + // Scans thru all obj lu and counts free, deleted and used pages // Find the maximum block erase count +// Checks magic if enabled s32_t spiffs_obj_lu_scan( spiffs *fs) { s32_t res; spiffs_block_ix bix; int entry; +#if SPIFFS_USE_MAGIC + spiffs_block_ix unerased_bix = (spiffs_block_ix)-1; +#endif - fs->free_blocks = 0; - fs->stats_p_allocated = 0; - fs->stats_p_deleted = 0; - - res = spiffs_obj_lu_find_entry_visitor(fs, - 0, - 0, - 0, - 0, - spiffs_obj_lu_scan_v, - 0, - 0, - &bix, - &entry); - - if (res == SPIFFS_VIS_END) { - res = SPIFFS_OK; - } - - SPIFFS_CHECK_RES(res); - + // find out erase count + // if enabled, check magic bix = 0; spiffs_obj_id erase_count_final; spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE; spiffs_obj_id erase_count_max = 0; while (bix < fs->block_count) { +#if SPIFFS_USE_MAGIC + spiffs_obj_id magic; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_MAGIC_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&magic); + + SPIFFS_CHECK_RES(res); + if (magic != SPIFFS_MAGIC(fs)) { + if (unerased_bix == (spiffs_block_ix)-1) { + // allow one unerased block as it might be powered down during an erase + unerased_bix = bix; + } else { + // more than one unerased block, bail out + SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS); + } + } +#endif spiffs_obj_id erase_count; res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, @@ -297,6 +340,38 @@ s32_t spiffs_obj_lu_scan( fs->max_erase_count = erase_count_final; +#if SPIFFS_USE_MAGIC + if (unerased_bix != (spiffs_block_ix)-1) { + // found one unerased block, remedy + SPIFFS_DBG("mount: erase block %i\n", bix); + res = spiffs_erase_block(fs, unerased_bix); + SPIFFS_CHECK_RES(res); + } +#endif + + // count blocks + + fs->free_blocks = 0; + fs->stats_p_allocated = 0; + fs->stats_p_deleted = 0; + + res = spiffs_obj_lu_find_entry_visitor(fs, + 0, + 0, + 0, + 0, + spiffs_obj_lu_scan_v, + 0, + 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + SPIFFS_CHECK_RES(res); + return res; } diff --git a/app/spiffs/spiffs_nucleus.h b/app/spiffs/spiffs_nucleus.h index cc414432..7a98a330 100644 --- a/app/spiffs/spiffs_nucleus.h +++ b/app/spiffs/spiffs_nucleus.h @@ -131,6 +131,10 @@ #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) +#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) + +#define SPIFFS_CONFIG_MAGIC (0x20090315) + #if SPIFFS_SINGLETON == 0 #define SPIFFS_CFG_LOG_PAGE_SZ(fs) \ ((fs)->cfg.log_page_size) @@ -189,9 +193,18 @@ // returns data size in a data page #define SPIFFS_DATA_PAGE_SIZE(fs) \ ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) ) -// returns physical address for block's erase count +// returns physical address for block's erase count, +// always in the physical last entry of the last object lookup page #define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \ ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) ) +// returns physical address for block's magic, +// always in the physical second last entry of the last object lookup page +#define SPIFFS_MAGIC_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 ) +// checks if there is any room for magic in the object luts +#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \ + ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \ + <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) ) // define helpers object @@ -238,7 +251,10 @@ #define SPIFFS_CHECK_MOUNT(fs) \ - ((fs)->block_count > 0) + ((fs)->mounted != 0) + +#define SPIFFS_CHECK_CFG(fs) \ + ((fs)->config_magic == SPIFFS_CONFIG_MAGIC) #define SPIFFS_CHECK_RES(res) \ do { \ @@ -251,6 +267,12 @@ return -1; \ } +#define SPIFFS_API_CHECK_CFG(fs) \ + if (!SPIFFS_CHECK_CFG((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \ + return -1; \ + } + #define SPIFFS_API_CHECK_RES(fs, res) \ if ((res) < SPIFFS_OK) { \ (fs)->err_code = (res); \ @@ -381,6 +403,8 @@ typedef struct { // object structs // page header, part of each page except object lookup pages +// NB: this is always aligned when the data page is an object index, +// as in this case struct spiffs_page_object_ix is used typedef struct __attribute(( packed )) { // object id spiffs_obj_id obj_id; @@ -391,11 +415,15 @@ typedef struct __attribute(( packed )) { } spiffs_page_header; // object index header page header -typedef struct __attribute(( packed )) { +typedef struct __attribute(( packed )) +#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES + __attribute(( aligned(sizeof(spiffs_page_ix)) )) +#endif +{ // common page header spiffs_page_header p_hdr; // alignment - u8_t _align[4 - ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)==0 ? 4 : ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&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 @@ -478,6 +506,10 @@ s32_t spiffs_obj_lu_find_entry_visitor( spiffs_block_ix *block_ix, int *lu_entry); +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix); + // --------------- s32_t spiffs_obj_lu_scan( diff --git a/app/spiffs/test/params_test.h b/app/spiffs/test/params_test.h index 241367f3..ad51f573 100644 --- a/app/spiffs/test/params_test.h +++ b/app/spiffs/test/params_test.h @@ -15,6 +15,9 @@ // spiffs file system offset in emulated spi flash #define SPIFFS_PHYS_ADDR (4*1024*1024) +// test using filesystem magic +//#define SPIFFS_USE_MAGIC 1 + #define SECTOR_SIZE 65536 #define LOG_BLOCK (SECTOR_SIZE*2) #define LOG_PAGE (SECTOR_SIZE/256) diff --git a/app/spiffs/test/test_bugreports.c b/app/spiffs/test/test_bugreports.c index b577e6f7..82ad97de 100644 --- a/app/spiffs/test/test_bugreports.c +++ b/app/spiffs/test/test_bugreports.c @@ -157,4 +157,19 @@ TEST(nodemcu_full_fs_2) { } TEST_END(nodemcu_full_fs_2) +TEST(magic_test) { + // one obj lu page, not full + fs_reset_specific(0, 4096*16, 4096, 4096*1, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // one obj lu page, full + fs_reset_specific(0, 4096*16, 4096, 4096*2, 128); + TEST_CHECK(!SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // two obj lu pages, not full + fs_reset_specific(0, 4096*16, 4096, 4096*4, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + + return TEST_RES_OK; + +} TEST_END(magic_test) + SUITE_END(bug_tests) diff --git a/app/spiffs/test/test_spiffs.c b/app/spiffs/test/test_spiffs.c index 20335663..71e9e2d1 100644 --- a/app/spiffs/test/test_spiffs.c +++ b/app/spiffs/test/test_spiffs.c @@ -318,6 +318,7 @@ void fs_reset_specific(u32_t phys_addr, u32_t phys_size, u32_t log_block_size, u32_t log_page_size) { memset(area, 0xcc, sizeof(area)); memset(&area[phys_addr], 0xff, phys_size); + memset(&__fs, 0, sizeof(__fs)); spiffs_config c; c.hal_erase_f = _erase; @@ -332,7 +333,20 @@ void fs_reset_specific(u32_t phys_addr, u32_t phys_size, memset(erases,0,sizeof(erases)); memset(_cache,0,sizeof(_cache)); - SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f); + s32_t res = SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f); +#if SPIFFS_USE_MAGIC + if (res == SPIFFS_OK) { + SPIFFS_unmount(&__fs); + } + res = SPIFFS_format(&__fs); + if (res != SPIFFS_OK) { + printf("format failed, %i\n", SPIFFS_errno(&__fs)); + } + res = SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f); + if (res != SPIFFS_OK) { + printf("mount failed, %i\n", SPIFFS_errno(&__fs)); + } +#endif clear_flash_ops_log(); log_flash_ops = 1; @@ -574,6 +588,8 @@ void _teardown() { printf(" cache hits : %i (sum %i)\n", (FS)->cache_hits, chits_tot); printf(" cache misses : %i (sum %i)\n", (FS)->cache_misses, cmiss_tot); printf(" cache utiliz : %f\n", ((float)chits_tot/(float)(chits_tot + cmiss_tot))); + chits_tot = 0; + cmiss_tot = 0; #endif #endif dump_flash_access_stats(); diff --git a/lua_examples/mqtt/readme.md b/lua_examples/mqtt/readme.md new file mode 100644 index 00000000..47256eb6 --- /dev/null +++ b/lua_examples/mqtt/readme.md @@ -0,0 +1,38 @@ +####Connect to MQTT Broker + +```lua +-- init mqtt client with keepalive timer 120sec +m = mqtt.Client("clientid", 120, "user", "password") + +-- setup Last Will and Testament (optional) +-- Broker will publish a message with qos = 0, retain = 0, data = "offline" +-- to topic "/lwt" if client don't send keepalive packet +m:lwt("/lwt", "offline", 0, 0) + +m:on("connect", function(con) print ("connected") end) +m:on("offline", function(con) print ("offline") end) + +-- on publish message receive event +m:on("message", function(conn, topic, data) + print(topic .. ":" ) + if data ~= nil then + print(data) + end +end) + +-- m:connect( host, port, secure, auto_reconnect, function(client) ) +-- for secure: m:connect("192.168.11.118", 1880, 1, 0) +-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1) +m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end) + +-- subscribe topic with qos = 0 +m:subscribe("/topic",0, function(conn) print("subscribe success") end) +-- or subscribe multiple topic (topic/0, qos = 0; topic/1, qos = 1; topic2 , qos = 2) +-- m:subscribe({["topic/0"]=0,["topic/1"]=1,topic2=2}, function(conn) print("subscribe success") end) +-- publish a message with data = hello, QoS = 0, retain = 0 +m:publish("/topic","hello",0,0, function(conn) print("sent") end) + +m:close(); -- if auto-reconnect == 1, will disable auto-reconnect and then disconnect from host. +-- you can call m:connect again + +``` \ No newline at end of file