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