From a1e02fc6a898475316d18a27f61092eabcefccb0 Mon Sep 17 00:00:00 2001 From: petur Date: Sun, 25 Mar 2018 22:56:01 +0200 Subject: [PATCH 01/21] fix for ds18b20 negative decimals ds18b20 decimals do not take into account the sign bit. Since the original calculation was not so readable, rewritten in readable way that also fixes the bug. Same code as PR against master. --- app/modules/ds18b20.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/modules/ds18b20.c b/app/modules/ds18b20.c index b07bc173..a9df0ab1 100644 --- a/app/modules/ds18b20.c +++ b/app/modules/ds18b20.c @@ -192,6 +192,7 @@ static int ds18b20_lua_read(lua_State *L) { static int ds18b20_read_device(uint8_t *ds18b20_device_rom) { lua_State *L = lua_getstate(); + int16_t ds18b20_raw_temp; if (onewire_crc8(ds18b20_device_rom,7) == ds18b20_device_rom[7]) { @@ -216,8 +217,9 @@ static int ds18b20_read_device(uint8_t *ds18b20_device_rom) { lua_pushfstring(L, "%d:%d:%d:%d:%d:%d:%d:%d", ds18b20_device_rom[0], ds18b20_device_rom[1], ds18b20_device_rom[2], ds18b20_device_rom[3], ds18b20_device_rom[4], ds18b20_device_rom[5], ds18b20_device_rom[6], ds18b20_device_rom[7]); ds18b20_device_scratchpad_conf = (ds18b20_device_scratchpad[4] >> 5) + 9; - ds18b20_device_scratchpad_temp = ((int8_t)(ds18b20_device_scratchpad[1] << 4) + (ds18b20_device_scratchpad[0] >> 4) + ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16)); - ds18b20_device_scratchpad_temp_dec = ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16 * 1000); + ds18b20_raw_temp = ((ds18b20_device_scratchpad[1] << 8) | ds18b20_device_scratchpad[0]); + ds18b20_device_scratchpad_temp = (double)ds18b20_raw_temp / 16; + ds18b20_device_scratchpad_temp_dec = (ds18b20_raw_temp - (ds18b20_raw_temp / 16 * 16)) * 1000 / 16; if (ds18b20_device_scratchpad_conf >= ds18b20_device_res) { ds18b20_device_res = ds18b20_device_scratchpad_conf; From 085f35da73ae63357d9fc65eae002f3c1f27aeaf Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Fri, 6 Apr 2018 22:52:03 +1000 Subject: [PATCH 02/21] Tie in the EGC with the SDK's heap knowledge. (#2319) Added `node.egc.meminfo()` to expose LVM usage (to make the regular `node.egc.ON_MEM_LIMIT` option usable). Extended the `node.egc.ON_MEM_LIMIT` option to also take negative limits, in which case that's taken as a request to keep a certain amount of heap available for non-Lua use. --- app/lua/lauxlib.c | 6 ++++++ app/lua/legc.c | 2 +- app/lua/legc.h | 2 +- app/lua/lstate.h | 2 +- app/modules/node.c | 14 ++++++++++++-- docs/en/modules/node.md | 19 ++++++++++++++++++- 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/lua/lauxlib.c b/app/lua/lauxlib.c index bc9010fa..ce82ee29 100644 --- a/app/lua/lauxlib.c +++ b/app/lua/lauxlib.c @@ -14,6 +14,7 @@ #include C_HEADER_STRING #ifndef LUA_CROSS_COMPILER #include "vfs.h" +#include "user_interface.h" #else #endif @@ -791,6 +792,11 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { } if (L != NULL && (mode & EGC_ALWAYS)) /* always collect memory if requested */ luaC_fullgc(L); +#ifndef LUA_CROSS_COMPILER + if (L != NULL && (mode & EGC_ON_MEM_LIMIT) && G(L)->memlimit < 0 && + (system_get_free_heap_size() < (-G(L)->memlimit))) + luaC_fullgc(L); +#endif if(nsize > osize && L != NULL) { #if defined(LUA_STRESS_EMERGENCY_GC) luaC_fullgc(L); diff --git a/app/lua/legc.c b/app/lua/legc.c index d2285ca4..fdee4832 100644 --- a/app/lua/legc.c +++ b/app/lua/legc.c @@ -4,7 +4,7 @@ #include "lstate.h" #include "c_types.h" -void legc_set_mode(lua_State *L, int mode, unsigned limit) { +void legc_set_mode(lua_State *L, int mode, int limit) { global_State *g = G(L); g->egcmode = mode; diff --git a/app/lua/legc.h b/app/lua/legc.h index a0d9dde3..c85ebb6b 100644 --- a/app/lua/legc.h +++ b/app/lua/legc.h @@ -11,7 +11,7 @@ #define EGC_ON_MEM_LIMIT 2 // run EGC when an upper memory limit is hit #define EGC_ALWAYS 4 // always run EGC before an allocation -void legc_set_mode(lua_State *L, int mode, unsigned limit); +void legc_set_mode(lua_State *L, int mode, int limit); #endif diff --git a/app/lua/lstate.h b/app/lua/lstate.h index 1b3c363a..97a1a4b2 100644 --- a/app/lua/lstate.h +++ b/app/lua/lstate.h @@ -82,7 +82,7 @@ typedef struct global_State { Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem totalbytes; /* number of bytes currently allocated */ - lu_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. */ + l_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. <0 used with EGC_ON_MEM_LIMIT when free heap falls below -memlimit */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem gcdept; /* how much GC is `behind schedule' */ int gcpause; /* size of pause between successive GCs */ diff --git a/app/modules/node.c b/app/modules/node.c index 8302ec8c..1f207465 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -462,14 +462,23 @@ static int node_stripdebug (lua_State *L) { // See legc.h and lecg.c. static int node_egc_setmode(lua_State* L) { unsigned mode = luaL_checkinteger(L, 1); - unsigned limit = luaL_optinteger (L, 2, 0); + int limit = luaL_optinteger (L, 2, 0); luaL_argcheck(L, mode <= (EGC_ON_ALLOC_FAILURE | EGC_ON_MEM_LIMIT | EGC_ALWAYS), 1, "invalid mode"); - luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit>0, 1, "limit must be non-zero"); + luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit!=0, 1, "limit must be non-zero"); legc_set_mode( L, mode, limit ); return 0; } + +// totalallocated, estimatedused = node.egc.meminfo() +static int node_egc_meminfo(lua_State *L) { + global_State *g = G(L); + lua_pushinteger(L, g->totalbytes); + lua_pushinteger(L, g->estimate); + return 2; +} + // // Lua: osprint(true/false) // Allows you to turn on the native Espressif SDK printing @@ -560,6 +569,7 @@ static int node_random (lua_State *L) { // Module function map static const LUA_REG_TYPE node_egc_map[] = { + { LSTRKEY( "meminfo" ), LFUNCVAL( node_egc_meminfo ) }, { LSTRKEY( "setmode" ), LFUNCVAL( node_egc_setmode ) }, { LSTRKEY( "NOT_ACTIVE" ), LNUMVAL( EGC_NOT_ACTIVE ) }, { LSTRKEY( "ON_ALLOC_FAILURE" ), LNUMVAL( EGC_ON_ALLOC_FAILURE ) }, diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index e34c31f3..2e1d092f 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -484,7 +484,7 @@ provides more detailed information on the EGC. - `mode` - `node.egc.NOT_ACTIVE` EGC inactive, no collection cycle will be forced in low memory situations - `node.egc.ON_ALLOC_FAILURE` Try to allocate a new block of memory, and run the garbage collector if the allocation fails. If the allocation fails even after running the garbage collector, the allocator will return with error. - - `node.egc.ON_MEM_LIMIT` Run the garbage collector when the memory used by the Lua script goes beyond an upper `limit`. If the upper limit can't be satisfied even after running the garbage collector, the allocator will return with error. + - `node.egc.ON_MEM_LIMIT` Run the garbage collector when the memory used by the Lua script goes beyond an upper `limit`. If the upper limit can't be satisfied even after running the garbage collector, the allocator will return with error. If the given limit is negative, it is interpreted as the desired amount of heap which should be left available. Whenever the free heap (as reported by `node.heap()` falls below the requested limit, the garbage collector will be run. - `node.egc.ALWAYS` Run the garbage collector before each memory allocation. If the allocation fails even after running the garbage collector, the allocator will return with error. This mode is very efficient with regards to memory savings, but it's also the slowest. - `level` in the case of `node.egc.ON_MEM_LIMIT`, this specifies the memory limit. @@ -495,6 +495,23 @@ provides more detailed information on the EGC. `node.egc.setmode(node.egc.ALWAYS, 4096) -- This is the default setting at startup.` `node.egc.setmode(node.egc.ON_ALLOC_FAILURE) -- This is the fastest activeEGC mode.` +`node.egc.setmode(node.egc.ON_MEM_LIMIT, 30720) -- Only allow the Lua runtime to allocate at most 30k, collect garbage if limit is about to be hit` +`node.egc.setmode(node.egc.ON_MEM_LIMIT, -6144) -- Try to keep at least 6k heap available for non-Lua use (e.g. network buffers)` + + +## node.egc.meminfo() + +Returns memory usage information for the Lua runtime. + +####Syntax +`total_allocated, estimated_used = node.egc.meminfo()` + +#### Parameters +None. + +#### Returns + - `total_allocated` The total number of bytes allocated by the Lua runtime. This is the number which is relevant when using the `node.egc.ON_MEM_LIMIT` option with positive limit values. + - `estimated_used` This value shows the estimated usage of the allocated memory. # node.task module From cb2808835d01758a8ba4e350e65c66b879f6187a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Fri, 6 Apr 2018 17:35:11 +0200 Subject: [PATCH 03/21] Fix Markdown syntax issues, fixes #2347 --- lua_modules/lm92/README.md | 144 +++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/lua_modules/lm92/README.md b/lua_modules/lm92/README.md index 896a609c..e2e6b2fb 100644 --- a/lua_modules/lm92/README.md +++ b/lua_modules/lm92/README.md @@ -6,7 +6,7 @@ Works: - entering the chip's to shutdown mode (350uA -> 5uA power consumption) - waking up the chip from shutdown -##Require +## Require ```lua LM92 = require("lm92") ``` @@ -16,19 +16,19 @@ LM92 = nil package.loaded["lm92"]=nil ``` -##setup() -####Description +## setup() +#### Description Setting the address for lm92. -####Syntax +#### Syntax setup(sda, scl, address) -####Parameters +#### Parameters address: 0x48~0x4b, i2c address (depends on tha A0~A1 pins) -####Returns +#### Returns nil -####Example +#### Example ```lua LM92 = require("lm92") gpio0 = 3 @@ -39,126 +39,126 @@ addr = 0x48 i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once LM92.setup(addr) ``` -##getTemperature() -####Description +## getTemperature() +#### Description Returns the temperature register's content. -####Syntax +#### Syntax getTemperature() -####Parameters +#### Parameters - -####Returns +#### Returns Temperature in degree Celsius. -####Example +#### Example ```lua t = LM92.getTemperature() print("Got temperature: "..t.." C") ``` -##wakeup() -####Description +## wakeup() +#### Description Makes the chip exit the low power shutdown mode. -####Syntax +#### Syntax wakeup() -####Parameters +#### Parameters - -####Returns +#### Returns - -####Example +#### Example ```lua LM92.wakeup() tmr.delay( 1 * 1000 * 1000 ) ``` -##shutdown() -####Description +## shutdown() +#### Description Makes the chip enter the low power shutdown mode. -####Syntax +#### Syntax shutdown() -####Parameters +#### Parameters - -####Returns +#### Returns - -####Example +#### Example ```lua LM92.shutdown() ``` -##setThyst() -####Description +## setThyst() +#### Description Set hysteresis Temperature. -####Syntax +#### Syntax setThyst(data_wr) -####Parameters +#### Parameters data_wr: 130~-55 ºC, hysteresis Temperature -####Returns +#### Returns nil -####Example +#### Example ```lua LM92.setThyst(3) ``` -##setTcrit() -####Description +## setTcrit() +#### Description Set Critical Temperature. -####Syntax +#### Syntax setTcrit(data_wr) -####Parameters +#### Parameters data_wr: 130~-55 ºC, Critical Temperature -####Returns +#### Returns nil -####Example +#### Example ```lua LM92.setTcrit(100.625) ``` -##setTlow() -####Description +## setTlow() +#### Description Set Low Window Temperature. -####Syntax +#### Syntax setTlow(data_wr) ####Parameters data_wr: 130~-55 ºC, Low Window Temperature -####Returns +#### Returns nil -####Example +#### Example ```lua LM92.setTlow(32.25) ``` -##setThigh() +## setThigh() ####Description Set High Window Temperature. -####Syntax +#### Syntax setThigh(data_wr) -####Parameters +#### Parameters data_wr: 130~-55 ºC, High Window Temperature -####Returns +#### Returns nil ####Example @@ -166,83 +166,84 @@ nil LM92.setThigh(27.5) ``` -##getThyst() -####Description +## getThyst() +#### Description Get hysteresis Temperature. -####Syntax +#### Syntax getThyst() -####Parameters +#### Parameters -- -####Returns +#### Returns Hysteresis Temperature in degree Celsius. -####Example +#### Example ```lua t = LM92.getThyst() print("Got hysteresis temperature: "..t.." C") ``` -##getTcrit() -####Description +## getTcrit() +#### Description Get Critical Temperature. -####Syntax +#### Syntax getTcrit() -####Parameters +#### Parameters -- -####Returns +#### Returns Critical Temperature in degree Celsius. -####Example +#### Example ```lua t = LM92.getTcrit() print("Got Critical temperature: "..t.." C") ``` -##getTlow() -####Description +## getTlow() +#### Description Get Low Window Temperature. -####Syntax +#### Syntax getTlow() -####Parameters +#### Parameters -- -####Returns +#### Returns Low Window Temperature in degree Celsius. -####Example +#### Example ```lua t = LM92.getTlow() print("Got Low Window temperature: "..t.." C") ``` -##getThigh() -####Description +## getThigh() +#### Description Get High Window Temperature. -####Syntax +#### Syntax getThigh() -####Parameters +#### Parameters -- -####Returns +#### Returns High Window Temperature in degree Celsius. -####Example +#### Example ```lua t = LM92.getThigh() print("Got High Window temperature: "..t.." C") ``` -##Full example +## Full example +```lua --node.compile("lm92.lua") LM92 = require("lm92") gpio0 = 3 @@ -270,6 +271,7 @@ t = LM92.getTlow() print("Got Low: "..t.." C") t = LM92.getThigh() print("Got High: "..t.." C") +``` #### TODO: - add full support of the features, including interrupt and critical alert support From cda8da622d688c8ab3ad22c1e75e0584d7739087 Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Sat, 7 Apr 2018 16:44:42 -0400 Subject: [PATCH 04/21] Put each ICACHE_RAM_ATTR function in its own section. (#2334) * Put each ICACHE_RAM_ATTR function in its own section. * Chached the macro names to be less likely to cause problems --- app/include/user_config.h | 4 +++- ld/nodemcu.ld | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/include/user_config.h b/app/include/user_config.h index 0160d840..85db96d8 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -52,7 +52,9 @@ extern void luaL_assertfail(const char *file, int line, const char *message); #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) #define ICACHE_STORE_ATTR __attribute__((aligned(4))) -#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) +#define ICACHE_RAM_STRING(x) ICACHE_RAM_STRING2(x) +#define ICACHE_RAM_STRING2(x) #x +#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text." __FILE__ "." ICACHE_RAM_STRING(__LINE__)))) #ifdef GPIO_SAFE_NO_INTR_ENABLE #define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline)) #else diff --git a/ld/nodemcu.ld b/ld/nodemcu.ld index 9488045a..9c0a0dc1 100644 --- a/ld/nodemcu.ld +++ b/ld/nodemcu.ld @@ -121,7 +121,7 @@ SECTIONS /* *libwpa.a:*(.literal .text) - tested that safe to keep in iROM */ /* *libwps.a:*(.literal .text) - tested that safe to keep in iROM */ - *(.iram.text .iram0.text) + *(.iram.text .iram0.text .iram0.text.*) *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) From 81435ceecf7a95c570843cd7aa9f3e137f909ac9 Mon Sep 17 00:00:00 2001 From: philip Date: Thu, 12 Apr 2018 22:09:52 -0400 Subject: [PATCH 05/21] Missed setting the ID into the data block --- app/modules/rotary.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/modules/rotary.c b/app/modules/rotary.c index af60a4e3..cedb02fd 100644 --- a/app/modules/rotary.c +++ b/app/modules/rotary.c @@ -152,6 +152,8 @@ static int lrotary_setup( lua_State* L ) DATA *d = data[id]; memset(d, 0, sizeof(*d)); + d->id = id; + os_timer_setfn(&d->timer, lrotary_timer_done, (void *) d); int i; From 96e5c026a8d94b43aa0f804537891d149bbb9fa7 Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Fri, 13 Apr 2018 12:41:14 -0700 Subject: [PATCH 06/21] Refactor timer suspend portion of node.sleep (pmsleep) (#2287) * pmsleep refactor * Shortened swtmr disabled message * Added swtimer debug module option to user_modules.h. * Added comments to user_config.h. * Fixed error in documentation for node.sleep() * remove blank sntp.c that got added in during rebase onto dev(6218b92) * Added #ifdefs around SWTIMER_REG_CB to prevent inclusion of disabled code --- app/Makefile | 4 - app/coap/coap_timer.c | 3 + app/driver/key.c | 5 + app/driver/spi.c | 3 + app/driver/uart.c | 3 + app/http/httpclient.c | 3 + app/include/misc/dynarr.h | 40 -- app/{ => include}/pm/pmSleep.h | 0 app/include/pm/swtimer.h | 30 ++ app/include/rtc/rtctime_internal.h | 4 + app/include/swTimer/swTimer.h | 53 --- app/include/user_config.h | 4 +- app/include/user_modules.h | 4 + app/lwip/core/mdns.c | 3 + app/misc/Makefile | 52 --- app/misc/dyn_arr.c | 131 ------ app/modules/cron.c | 14 +- app/modules/ds18b20.c | 5 + app/modules/enduser_setup.c | 8 +- app/modules/mqtt.c | 4 + app/modules/node.c | 7 +- app/modules/rotary.c | 7 + app/modules/sntp.c | 7 + app/modules/tmr.c | 102 ++--- app/modules/wifi.c | 25 +- app/modules/ws2812_effects.c | 2 +- app/net/nodemcu_mdns.c | 4 + app/pm/pmSleep.c | 72 ++-- app/pm/swtimer.c | 545 +++++++++++++++++++++++++ app/smart/smart.c | 8 + app/swTimer/Makefile | 52 --- app/swTimer/swTimer.c | 632 ----------------------------- app/websocket/websocketclient.c | 5 + docs/en/modules/node.md | 42 +- docs/en/modules/tmr.md | 123 ------ sdk-overrides/include/osapi.h | 11 - 36 files changed, 772 insertions(+), 1245 deletions(-) delete mode 100644 app/include/misc/dynarr.h rename app/{ => include}/pm/pmSleep.h (100%) create mode 100644 app/include/pm/swtimer.h delete mode 100644 app/include/swTimer/swTimer.h delete mode 100644 app/misc/Makefile delete mode 100644 app/misc/dyn_arr.c create mode 100644 app/pm/swtimer.c delete mode 100644 app/swTimer/Makefile delete mode 100644 app/swTimer/swTimer.c diff --git a/app/Makefile b/app/Makefile index ee472211..51c50ccd 100644 --- a/app/Makefile +++ b/app/Makefile @@ -46,8 +46,6 @@ SUBDIRS= \ fatfs \ esp-gdbstub \ websocket \ - swTimer \ - misc \ pm \ sjson \ sqlite3 \ @@ -102,8 +100,6 @@ COMPONENTS_eagle.app.v6 = \ net/libnodemcu_net.a \ mbedtls/libmbedtls.a \ modules/libmodules.a \ - swTimer/libswtimer.a \ - misc/libmisc.a \ sjson/libsjson.a \ sqlite3/libsqlite3.a \ diff --git a/app/coap/coap_timer.c b/app/coap/coap_timer.c index 9856ef83..5af84a0c 100644 --- a/app/coap/coap_timer.c +++ b/app/coap/coap_timer.c @@ -1,6 +1,7 @@ #include "node.h" #include "coap_timer.h" #include "os_type.h" +#include "pm/swtimer.h" static os_timer_t coap_timer; static coap_tick_t basetime = 0; @@ -48,6 +49,8 @@ void coap_timer_tick(void *arg){ void coap_timer_setup(coap_queue_t ** queue, coap_tick_t t){ os_timer_disarm(&coap_timer); os_timer_setfn(&coap_timer, (os_timer_func_t *)coap_timer_tick, queue); + SWTIMER_REG_CB(coap_timer_tick, SWTIMER_RESUME); + //coap_timer_tick processes a queue, my guess is that it is ok to resume the timer from where it left off os_timer_arm(&coap_timer, t, 0); // no repeat } diff --git a/app/driver/key.c b/app/driver/key.c index 15806514..202becc2 100644 --- a/app/driver/key.c +++ b/app/driver/key.c @@ -14,6 +14,7 @@ #include "mem.h" #include "gpio.h" #include "user_interface.h" +#include "pm/swtimer.h" #include "driver/key.h" @@ -148,6 +149,8 @@ key_intr_handler(void *arg) // 5s, restart & enter softap mode os_timer_disarm(&keys->single_key[i]->key_5s); os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]); + SWTIMER_REG_CB(key_5s_cb, SWTIMER_DROP); + // key_5s_cb checks the state of a gpio. After resume, gpio state would be invalid os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0); keys->single_key[i]->key_level = 0; gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE); @@ -155,6 +158,8 @@ key_intr_handler(void *arg) // 50ms, check if this is a real key up os_timer_disarm(&keys->single_key[i]->key_50ms); os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]); + SWTIMER_REG_CB(key_50ms_cb, SWTIMER_DROP); + // key_50ms_cb checks the state of a gpio. After resume, gpio state would be invalid os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0); } } diff --git a/app/driver/spi.c b/app/driver/spi.c index 41f2544d..1e2f1972 100644 --- a/app/driver/spi.c +++ b/app/driver/spi.c @@ -527,6 +527,7 @@ void spi_slave_init(uint8 spi_no) #ifdef SPI_SLAVE_DEBUG +#include "pm/swtimer.h" /****************************************************************************** * FunctionName : hspi_master_readwrite_repeat * Description : SPI master test function for reading and writing esp8266 slave buffer, @@ -545,6 +546,8 @@ void hspi_master_readwrite_repeat(void) temp++; spi_byte_write_espslave(SPI_HSPI,temp); os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL); + SWTIMER_REGISTER_CB_PTR(hspi_master_readwrite_repeat, SWTIMER_RESUME); + //hspi_master_readwrite_repeat timer will be resumed on wake up, maybe data will still be in buffer? os_timer_arm(&timer2, 500, 0); } #endif diff --git a/app/driver/uart.c b/app/driver/uart.c index 379d3da0..61b299a5 100755 --- a/app/driver/uart.c +++ b/app/driver/uart.c @@ -323,11 +323,14 @@ uart_autobaud_timeout(void *timer_arg) uart_div_modify(uart_no, divisor); } } +#include "pm/swtimer.h" static void uart_init_autobaud(uint32_t uart_no) { os_timer_setfn(&autobaud_timer, uart_autobaud_timeout, (void *) uart_no); + SWTIMER_REG_CB(uart_autobaud_timeout, SWTIMER_DROP); + //if autobaud hasn't done it's thing by the time light sleep triggered, it probably isn't going to happen. os_timer_arm(&autobaud_timer, 100, TRUE); } diff --git a/app/http/httpclient.c b/app/http/httpclient.c index 6c8d97c0..4e773bbc 100644 --- a/app/http/httpclient.c +++ b/app/http/httpclient.c @@ -20,6 +20,7 @@ #include "limits.h" #include "httpclient.h" #include "stdlib.h" +#include "pm/swtimer.h" #define REDIRECTION_FOLLOW_MAX 20 @@ -525,6 +526,8 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_ /* Set connection timeout timer */ os_timer_disarm( &(req->timeout_timer) ); os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn ); + SWTIMER_REG_CB(http_timeout_callback, SWTIMER_IMMEDIATE); + //http_timeout_callback frees memory used by this function and timer cannot be dropped os_timer_arm( &(req->timeout_timer), req->timeout, false ); #ifdef CLIENT_SSL_ENABLE diff --git a/app/include/misc/dynarr.h b/app/include/misc/dynarr.h deleted file mode 100644 index 4eb1b130..00000000 --- a/app/include/misc/dynarr.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __DYNARR_H__ -#define __DYNARR_H__ -#include "user_interface.h" -#include "c_stdio.h" -#include "c_stdlib.h" - -//#define DYNARR_DEBUG -//#define DYNARR_ERROR - - -typedef struct _dynarr{ - void* data_ptr; - size_t used; - size_t array_size; - size_t data_size; -} dynarr_t; - -bool dynarr_init(dynarr_t* array_ptr, size_t array_size, size_t data_size); -bool dynarr_resize(dynarr_t* array_ptr, size_t elements_to_add); -bool dynarr_remove(dynarr_t* array_ptr, void* element_ptr); -bool dynarr_add(dynarr_t* array_ptr, void* data_ptr, size_t data_size); -bool dynarr_boundaryCheck(dynarr_t* array_ptr, void* element_ptr); -bool dynarr_free(dynarr_t* array_ptr); - - -#if 0 || defined(DYNARR_DEBUG) || defined(NODE_DEBUG) -#define DYNARR_DBG(fmt, ...) c_printf("\n DYNARR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__) -#else -#define DYNARR_DBG(...) - -#endif - -#if 0 || defined(DYNARR_ERROR) || defined(NODE_ERROR) -#define DYNARR_ERR(fmt, ...) c_printf("\n DYNARR: "fmt"\n", ##__VA_ARGS__) -#else -#define DYNARR_ERR(...) - -#endif - -#endif // __DYNARR_H__ diff --git a/app/pm/pmSleep.h b/app/include/pm/pmSleep.h similarity index 100% rename from app/pm/pmSleep.h rename to app/include/pm/pmSleep.h diff --git a/app/include/pm/swtimer.h b/app/include/pm/swtimer.h new file mode 100644 index 00000000..6c0d84b2 --- /dev/null +++ b/app/include/pm/swtimer.h @@ -0,0 +1,30 @@ +/* + * swtimer.h + * + * Created on: Aug 4, 2017 + * Author: anonymous + */ + +#ifndef APP_INCLUDE_PM_SWTIMER_H_ +#define APP_INCLUDE_PM_SWTIMER_H_ + +void swtmr_cb_register(void* timer_cb_ptr, uint8 suspend_policy); + +#define SWTIMER_RESUME 0 //save remaining time +#define SWTIMER_RESTART 1 //use timer_period as remaining time +#define SWTIMER_IMMEDIATE 2 //fire timer immediately after resume +#define SWTIMER_DROP 3 //disarm timer, do not resume + +#if defined(TIMER_SUSPEND_ENABLE) +#define SWTIMER_REG_CB(cb_ptr, suspend_policy) do{ \ + static bool cb_ptr##_registered_flag;\ + if(!cb_ptr##_registered_flag){ \ + cb_ptr##_registered_flag = true; \ + swtmr_cb_register(cb_ptr, suspend_policy);\ + } \ +}while(0); +#else +#define SWTIMER_REG_CB(...) +#endif + +#endif /* APP_INCLUDE_PM_SWTIMER_H_ */ diff --git a/app/include/rtc/rtctime_internal.h b/app/include/rtc/rtctime_internal.h index a7a48621..f24e1741 100644 --- a/app/include/rtc/rtctime_internal.h +++ b/app/include/rtc/rtctime_internal.h @@ -689,11 +689,15 @@ static inline void rtc_time_switch_to_system_clock(void) static inline void rtc_time_tmrfn(void* arg); +#include "pm/swtimer.h" + static void rtc_time_install_timer(void) { static ETSTimer tmr; os_timer_setfn(&tmr,rtc_time_tmrfn,NULL); + SWTIMER_REG_CB(rtc_time_tmrfn, SWTIMER_RESUME); + //I believe the function rtc_time_tmrfn compensates for drift in the clock and updates rtc time accordingly, This timer should probably be resumed os_timer_arm(&tmr,10000,1); } diff --git a/app/include/swTimer/swTimer.h b/app/include/swTimer/swTimer.h deleted file mode 100644 index abbd3745..00000000 --- a/app/include/swTimer/swTimer.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __SW_TIMER_H__ -#define __SW_TIMER_H__ -#include "user_interface.h" -//#define SWTMR_DEBUG -#define USE_SWTMR_ERROR_STRINGS - -#if defined(DEVELOP_VERSION) -#define SWTMR_DEBUG -#endif - -#if defined(SWTMR_DEBUG) - #define SWTMR_DBG(fmt, ...) dbg_printf("\tSWTIMER(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__) -#else - #define SWTMR_DBG(...) -#endif - -#if defined(NODE_ERROR) - #define SWTMR_ERR(fmt, ...) NODE_ERR("%s"fmt"\n", "SWTIMER:", ##__VA_ARGS__) -#else - #define SWTMR_ERR(...) -#endif - -enum SWTMR_STATUS{ - SWTMR_FAIL = 0, - SWTMR_OK = 1, - - SWTMR_MALLOC_FAIL = 10, - SWTMR_TIMER_NOT_ARMED, -// SWTMR_NULL_PTR, - - SWTMR_REGISTRY_NO_REGISTERED_TIMERS, - -// SWTMR_SUSPEND_ARRAY_INITIALIZATION_FAILED, -// SWTMR_SUSPEND_ARRAY_ADD_FAILED, -// SWTMR_SUSPEND_ARRAY_REMOVE_FAILED, - SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED, - SWTMR_SUSPEND_TIMER_ALREADY_REARMED, - SWTMR_SUSPEND_NO_SUSPENDED_TIMERS, - SWTMR_SUSPEND_TIMER_NOT_SUSPENDED, - -}; - -/* Global Function Declarations */ -void swtmr_register(void* timer_ptr); -void swtmr_unregister(void* timer_ptr); -int swtmr_suspend(os_timer_t* timer_ptr); -int swtmr_resume(os_timer_t* timer_ptr); -void swtmr_print_registry(void); -void swtmr_print_suspended(void); -void swtmr_print_timer_list(void); -const char* swtmr_errorcode2str(int error_value); -bool swtmr_suspended_test(os_timer_t* timer_ptr); -#endif // __SW_TIMER_H__ diff --git a/app/include/user_config.h b/app/include/user_config.h index 85db96d8..e0abceca 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -116,8 +116,8 @@ extern void luaL_assertfail(const char *file, int line, const char *message); #define WIFI_SDK_EVENT_MONITOR_ENABLE #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE -////#define ENABLE_TIMER_SUSPEND -//#define PMSLEEP_ENABLE +//#define PMSLEEP_ENABLE // Enable wifi.suspend() and node.sleep() (NOTE: node.sleep() is dependent on TIMER_SUSPEND_ENABLE) +//#define TIMER_SUSPEND_ENABLE //Required by node.sleep() #define STRBUF_DEFAULT_INCREMENT 32 diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 1afdde13..0d4b9e91 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -86,5 +86,9 @@ //#define LUA_USE_MODULES_WS2812_EFFECTS //#define LUA_USE_MODULES_XPT2046 +//debug modules +//#define LUA_USE_MODULES_SWTMR_DBG //SWTMR timer suspend Debug functions + + #endif /* LUA_CROSS_COMPILER */ #endif /* __USER_MODULES_H__ */ diff --git a/app/lwip/core/mdns.c b/app/lwip/core/mdns.c index 635da3ca..49d939d3 100644 --- a/app/lwip/core/mdns.c +++ b/app/lwip/core/mdns.c @@ -1039,6 +1039,7 @@ mdns_reg(struct mdns_info *info) { os_timer_disarm(&mdns_timer); } } +#include "pm/swtimer.h" /** * Initialize the resolver: set up the UDP pcb and configure the default server @@ -1129,6 +1130,8 @@ mdns_init(struct mdns_info *info) { os_timer_disarm(&mdns_timer); os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info); + SWTIMER_REG_CB(mdns_reg, SWTIMER_RESTART); + //going on the above comment, it's probably a good idea to let mdns_reg run it's course. not sure if the 1 second timing is important, so lets restart it to be safe. os_timer_arm(&mdns_timer, 1000, 1); } } diff --git a/app/misc/Makefile b/app/misc/Makefile deleted file mode 100644 index 3a758dde..00000000 --- a/app/misc/Makefile +++ /dev/null @@ -1,52 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR -GEN_LIBS = libmisc.a -endif - -STD_CFLAGS=-std=gnu11 -Wimplicit - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -INCLUDES += -I ./ -INCLUDES += -I ./include -INCLUDES += -I ../include -INCLUDES += -I ../../include -INCLUDES += -I ../lua -INCLUDES += -I ../platform -INCLUDES += -I ../libc - -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/app/misc/dyn_arr.c b/app/misc/dyn_arr.c deleted file mode 100644 index b6ebb8c9..00000000 --- a/app/misc/dyn_arr.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "misc/dynarr.h" - -#define ARRAY_PTR_CHECK if(array_ptr == NULL || array_ptr->data_ptr == NULL){\ - /**/DYNARR_DBG("array not initialized");\ - return false; \ - } - -bool dynarr_init(dynarr_t* array_ptr, size_t array_size, size_t data_size){ - if(array_ptr == NULL || data_size == 0 || array_size == 0){ - /**/DYNARR_DBG("Invalid parameter: array_ptr(%p) data_size(%u) array_size(%u)", array_ptr, data_size, array_size); - return false; - } - if(array_ptr->data_ptr != NULL ){ - /**/DYNARR_DBG("Array already initialized: array_ptr->data_ptr=%p", array_ptr->data_ptr); - return false; - } - /**/DYNARR_DBG("Array parameters:\n\t\t\tarray_size(%u)\n\t\t\tdata_size(%u)\n\t\t\ttotal size(bytes):%u", array_size, data_size, (array_size * data_size)); - - void* temp_array = c_zalloc(array_size * data_size); - if(temp_array == NULL){ - /**/DYNARR_ERR("malloc FAIL! req:%u free:%u", (array_size * data_size), system_get_free_heap_size()); - return false; - } - - array_ptr->data_ptr = temp_array; - array_ptr->array_size = array_size; - array_ptr->data_size = data_size; - array_ptr->used = 0; - - return true; -} - -bool dynarr_resize(dynarr_t* array_ptr, size_t elements_to_add){ - ARRAY_PTR_CHECK; - - if(elements_to_add <= 0){ - /**/DYNARR_DBG("Invalid qty: elements_to_add=%u", elements_to_add); - return false; - } - - size_t new_array_size = array_ptr->array_size + elements_to_add; - - /**/DYNARR_DBG("old size=%u\tnew size=%u\tmem used=%u", - array_ptr->array_size, new_array_size, (new_array_size * array_ptr->data_size)); - - void* temp_array_p = c_realloc(array_ptr->data_ptr, new_array_size * array_ptr->data_size); - if(temp_array_p == NULL){ - /**/DYNARR_ERR("malloc FAIL! req:%u free:%u", (new_array_size * array_ptr->data_size), system_get_free_heap_size()); - return false; - } - - array_ptr->data_ptr = temp_array_p; - - size_t prev_size = array_ptr->array_size; - - array_ptr->array_size = new_array_size; - - //set memory to 0 for newly added array elements - memset((uint8*) array_ptr->data_ptr + (prev_size * array_ptr->data_size), 0, (elements_to_add * array_ptr->data_size)); - - /**/DYNARR_DBG("Array successfully resized"); - return true; -} - -bool dynarr_remove(dynarr_t* array_ptr, void* element_to_remove){ - ARRAY_PTR_CHECK; - - uint8* element_ptr = element_to_remove; - uint8* data_ptr = array_ptr->data_ptr; - - if(dynarr_boundaryCheck(array_ptr, element_to_remove) == FALSE){ - return false; - } - - //overwrite element to be removed by shifting all elements to the left - memmove(element_ptr, element_ptr + array_ptr->data_size, (array_ptr->array_size - 1) * array_ptr->data_size - (element_ptr - data_ptr)); - - //clear newly freed element - memset(data_ptr + ((array_ptr->array_size-1) * array_ptr->data_size), 0, array_ptr->data_size); - - //decrement array used since we removed an element - array_ptr->used--; - /**/DYNARR_DBG("element(%p) removed from array", element_ptr); - return true; -} - -bool dynarr_add(dynarr_t* array_ptr, void* data_ptr, size_t data_size){ - ARRAY_PTR_CHECK; - - if(data_size != array_ptr->data_size){ - /**/DYNARR_DBG("Invalid data size: data_size(%u) != arr->data_size(%u)", data_size, array_ptr->data_size); - return false; - } - - if(array_ptr->array_size == array_ptr->used){ - if(!dynarr_resize(array_ptr, (array_ptr->array_size/2))){ - return false; - } - } - memcpy(((uint8*)array_ptr->data_ptr + (array_ptr->used * array_ptr->data_size)), data_ptr, array_ptr->data_size); - - array_ptr->used++; - return true; -} - -bool dynarr_boundaryCheck(dynarr_t* array_ptr, void* element_to_check){ - ARRAY_PTR_CHECK; - - uint8* data_ptr = array_ptr->data_ptr; - uint8* element_ptr = element_to_check; - - if(element_ptr < data_ptr || ((element_ptr - data_ptr) / array_ptr->data_size) > array_ptr->array_size - 1){ - /**/DYNARR_DBG("element_ptr(%p) out of bounds: first element ptr:%p last element ptr:%p", - element_ptr, data_ptr, data_ptr + ((array_ptr->array_size - 1) * array_ptr->data_size)); - return false; - } - return true; -} - -bool dynarr_free(dynarr_t* array_ptr){ - ARRAY_PTR_CHECK; - - c_free(array_ptr->data_ptr); - - array_ptr->data_ptr=NULL; - array_ptr->array_size = array_ptr->used = 0; - - /**/DYNARR_DBG("array freed"); - return true; -} - diff --git a/app/modules/cron.c b/app/modules/cron.c index 4ba5d0bd..4a18a732 100644 --- a/app/modules/cron.c +++ b/app/modules/cron.c @@ -190,7 +190,7 @@ static void cron_handle_tmr() { struct rtc_timeval tv; rtctime_gettimeofday(&tv); if (tv.tv_sec == 0) { // Wait for RTC time - ets_timer_arm_new(&cron_timer, 1000, 0, 1); + os_timer_arm(&cron_timer, 1000, 0); return; } time_t t = tv.tv_sec; @@ -202,7 +202,7 @@ static void cron_handle_tmr() { diff += 60000; gmtime_r(&t, &tm); } - ets_timer_arm_new(&cron_timer, diff, 0, 1); + os_timer_arm(&cron_timer, diff, 0); cron_handle_time(tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, tm.tm_hour, tm.tm_min); } @@ -220,11 +220,15 @@ static const LUA_REG_TYPE cron_map[] = { { LSTRKEY( "reset" ), LFUNCVAL( lcron_reset ) }, { LNILKEY, LNILVAL } }; +#include "pm/swtimer.h" int luaopen_cron( lua_State *L ) { - ets_timer_disarm(&cron_timer); - ets_timer_setfn(&cron_timer, cron_handle_tmr, 0); - ets_timer_arm_new(&cron_timer, 1000, 0, 1); + os_timer_disarm(&cron_timer); + os_timer_setfn(&cron_timer, cron_handle_tmr, 0); + SWTIMER_REG_CB(cron_handle_tmr, SWTIMER_RESTART); + //cron_handle_tmr determines when to execute a scheduled cron job + //My guess: To be sure to give the other modules required by cron enough time to get to a ready state, restart cron_timer. + os_timer_arm(&cron_timer, 1000, 0); luaL_rometatable(L, "cron.entry", (void *)cronent_map); return 0; } diff --git a/app/modules/ds18b20.c b/app/modules/ds18b20.c index b07bc173..e7da45ca 100644 --- a/app/modules/ds18b20.c +++ b/app/modules/ds18b20.c @@ -134,6 +134,8 @@ static int ds18b20_lua_setting(lua_State *L) { return 0; } +#include "pm/swtimer.h" + // Reads sensor values from all devices // Lua: ds18b20.read(function(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) print(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) end, ROM[, FAMILY]) static int ds18b20_lua_read(lua_State *L) { @@ -173,6 +175,9 @@ static int ds18b20_lua_read(lua_State *L) { onewire_write(ds18b20_bus_pin, DS18B20_ROM_SKIP, 0); onewire_write(ds18b20_bus_pin, DS18B20_FUNC_CONVERT, 1); os_timer_setfn(&ds18b20_timer, (os_timer_func_t *)ds18b20_lua_readoutdone, NULL); + SWTIMER_REG_CB(ds18b20_lua_readoutdone, SWTIMER_DROP); + //The function ds18b20_lua_readoutdone reads the temperature from the sensor(s) after a set amount of time depending on temperature resolution + //MY guess: If this timer manages to get suspended before it fires and the temperature data is time sensitive then resulting data would be invalid and should be discarded switch (ds18b20_device_res) { case (9): diff --git a/app/modules/enduser_setup.c b/app/modules/enduser_setup.c index 5cd47f63..2cd52b3e 100644 --- a/app/modules/enduser_setup.c +++ b/app/modules/enduser_setup.c @@ -212,12 +212,15 @@ static void enduser_setup_connected_callback() } } - +#include "pm/swtimer.h" static void enduser_setup_check_station_start(void) { ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start"); os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL); + SWTIMER_REG_CB(enduser_setup_check_station, SWTIMER_RESUME); + //The function enduser_setup_check_station checks for a successful connection to the configured AP + //My guess: I'm not sure about whether or not user feedback is given via the web interface, but I don't see a problem with letting this timer resume. os_timer_arm(&(state->check_station_timer), 3*1000, TRUE); } @@ -317,6 +320,9 @@ static void enduser_setup_check_station(void *p) if (!manual) { os_timer_setfn(&(state->shutdown_timer), enduser_setup_stop_callback, NULL); + SWTIMER_REG_CB(enduser_setup_stop_callback, SWTIMER_RESUME); + //The function enduser_setup_stop_callback frees services and resources used by enduser setup. + //My guess: Since it would lead to a memory leak, it's probably best to resume this timer. os_timer_arm(&(state->shutdown_timer), 10*1000, FALSE); } } diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index f95fd3ae..eba227a4 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -981,6 +981,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) return espconn_status; } +#include "pm/swtimer.h" // Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client), function(client, connect_return_code) ) static int mqtt_socket_connect( lua_State* L ) { @@ -1114,6 +1115,9 @@ static int mqtt_socket_connect( lua_State* L ) os_timer_disarm(&mud->mqttTimer); os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); + SWTIMER_REG_CB(mqtt_socket_timer, SWTIMER_RESUME); + //I assume that mqtt_socket_timer connects to the mqtt server, but I'm not really sure what impact light_sleep will have on it. + //My guess: If in doubt, resume the timer // timer started in socket_connect() if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) diff --git a/app/modules/node.c b/app/modules/node.c index 1f207465..10e7a639 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -76,7 +76,7 @@ static int node_deepsleep( lua_State* L ) #ifdef PMSLEEP_ENABLE -#include "pmSleep.h" +#include "pm/pmSleep.h" int node_sleep_resume_cb_ref= LUA_NOREF; void node_sleep_resume_cb(void) @@ -89,6 +89,7 @@ void node_sleep_resume_cb(void) // Lua: node.sleep(table) static int node_sleep( lua_State* L ) { +#ifdef TIMER_SUSPEND_ENABLE pmSleep_INIT_CFG(cfg); cfg.sleep_mode=LIGHT_SLEEP_T; @@ -101,6 +102,10 @@ static int node_sleep( lua_State* L ) cfg.resume_cb_ptr = &node_sleep_resume_cb; pmSleep_suspend(&cfg); +#else + c_printf("\n The option \"timer_suspend_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n"); + return luaL_error(L, "light sleep is unavailable"); +#endif return 0; } #endif //PMSLEEP_ENABLE diff --git a/app/modules/rotary.c b/app/modules/rotary.c index cedb02fd..0b3f3278 100644 --- a/app/modules/rotary.c +++ b/app/modules/rotary.c @@ -129,6 +129,8 @@ int platform_rotary_exists( unsigned int id ) return (id < ROTARY_CHANNEL_COUNT); } +#include "pm/swtimer.h" + // Lua: setup(id, phase_a, phase_b [, press]) static int lrotary_setup( lua_State* L ) { @@ -155,6 +157,11 @@ static int lrotary_setup( lua_State* L ) d->id = id; os_timer_setfn(&d->timer, lrotary_timer_done, (void *) d); + SWTIMER_REG_CB(lrotary_timer_done, SWTIMER_RESUME); + //lrotary_timer_done checks time elapsed since last event + //My guess: Since proper functionality relies on some variables to be reset via timer callback and state would be invalid anyway. + //It is probably best to resume this timer so it can reset it's state variables + int i; for (i = 0; i < CALLBACK_COUNT; i++) { diff --git a/app/modules/sntp.c b/app/modules/sntp.c index b0e2033a..5614e4b4 100644 --- a/app/modules/sntp.c +++ b/app/modules/sntp.c @@ -319,6 +319,7 @@ static void sntp_handle_result(lua_State *L) { } } +#include "pm/swtimer.h" static void sntp_dosend () { @@ -326,6 +327,9 @@ static void sntp_dosend () if (state->server_pos < 0) { os_timer_disarm(&state->timer); os_timer_setfn(&state->timer, on_timeout, NULL); + SWTIMER_REG_CB(on_timeout, SWTIMER_RESUME); + //The function on_timeout calls this function(sntp_dosend) again to handle time sync timeout. + //My guess: Since the WiFi connection is restored after waking from light sleep, it would be possible to contact the SNTP server, So why not let it state->server_pos = 0; } else { ++state->server_pos; @@ -708,6 +712,9 @@ static char *set_repeat_mode(lua_State *L, bool enable) lua_rawgeti(L, LUA_REGISTRYINDEX, state->list_ref); repeat->list_ref = luaL_ref(L, LUA_REGISTRYINDEX); os_timer_setfn(&repeat->timer, on_long_timeout, NULL); + SWTIMER_REG_CB(on_long_timeout, SWTIMER_RESUME); + //The function on_long_timeout returns errors to the developer + //My guess: Error reporting is a good thing, resume the timer. os_timer_arm(&repeat->timer, 1000 * 1000, 1); } else { if (repeat) { diff --git a/app/modules/tmr.c b/app/modules/tmr.c index d8ec2ccd..125edd71 100755 --- a/app/modules/tmr.c +++ b/app/modules/tmr.c @@ -53,7 +53,7 @@ tmr.softwd(int) #include "platform.h" #include "c_types.h" #include "user_interface.h" -#include "swTimer/swTimer.h" +#include "pm/swtimer.h" #define TIMER_MODE_OFF 3 #define TIMER_MODE_SINGLE 0 @@ -231,68 +231,23 @@ static int tmr_stop(lua_State* L){ return 1; } -#ifdef ENABLE_TIMER_SUSPEND +#ifdef TIMER_SUSPEND_ENABLE +#define TMR_SUSPEND_REMOVED_MSG "This feature has been removed, we apologize for any inconvenience this may have caused." static int tmr_suspend(lua_State* L){ - timer_t tmr = tmr_get(L, 1); - - if((tmr->mode & TIMER_IDLE_FLAG) == 1){ - return luaL_error(L, "timer not armed"); - } - - int retval = swtmr_suspend(&tmr->os); - - if(retval != SWTMR_OK){ - return luaL_error(L, swtmr_errorcode2str(retval)); - } - else{ - lua_pushboolean(L, true); - } - - return 1; + return luaL_error(L, TMR_SUSPEND_REMOVED_MSG); } static int tmr_resume(lua_State* L){ - timer_t tmr = tmr_get(L, 1); - - if(swtmr_suspended_test(&tmr->os) == FALSE){ - return luaL_error(L, "timer not suspended"); - } - - int retval = swtmr_resume(&tmr->os); - - if(retval != SWTMR_OK){ - return luaL_error(L, swtmr_errorcode2str(retval)); - } - else{ - lua_pushboolean(L, true); - } - return 1; + return luaL_error(L, TMR_SUSPEND_REMOVED_MSG); } -static int tmr_suspend_all (lua_State *L) -{ - sint32 retval = swtmr_suspend(NULL); - // lua_pushnumber(L, swtmr_suspend(NULL)); - if(retval!=SWTMR_OK){ - return luaL_error(L, swtmr_errorcode2str(retval)); - } - else{ - lua_pushboolean(L, true); - } - return 1; +static int tmr_suspend_all (lua_State *L){ + return luaL_error(L, TMR_SUSPEND_REMOVED_MSG); } -static int tmr_resume_all (lua_State *L) -{ - sint32 retval = swtmr_resume(NULL); - if(retval!=SWTMR_OK){ - return luaL_error(L, swtmr_errorcode2str(retval)); - } - else{ - lua_pushboolean(L, true); - } - return 1; +static int tmr_resume_all (lua_State *L){ + return luaL_error(L, TMR_SUSPEND_REMOVED_MSG); } @@ -343,12 +298,7 @@ static int tmr_state(lua_State* L){ lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0); lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG)); -#ifdef ENABLE_TIMER_SUSPEND - lua_pushboolean(L, swtmr_suspended_test(&tmr->os)); -#else - lua_pushnil(L); -#endif - return 3; + return 2; } /*I left the led comments 'couse I don't know @@ -454,7 +404,7 @@ static const LUA_REG_TYPE tmr_dyn_map[] = { { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) }, { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) }, { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) }, -#ifdef ENABLE_TIMER_SUSPEND +#ifdef TIMER_SUSPEND_ENABLE { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, #endif @@ -463,15 +413,6 @@ static const LUA_REG_TYPE tmr_dyn_map[] = { { LNILKEY, LNILVAL } }; -#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG) -static const LUA_REG_TYPE tmr_dbg_map[] = { - { LSTRKEY( "printRegistry" ), LFUNCVAL( tmr_printRegistry ) }, - { LSTRKEY( "printSuspended" ), LFUNCVAL( tmr_printSuspended ) }, - { LSTRKEY( "printTimerlist" ), LFUNCVAL( tmr_printTimerlist ) }, - { LNILKEY, LNILVAL } -}; -#endif - static const LUA_REG_TYPE tmr_map[] = { { LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) }, { LSTRKEY( "now" ), LFUNCVAL( tmr_now ) }, @@ -482,7 +423,7 @@ static const LUA_REG_TYPE tmr_map[] = { { LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) }, { LSTRKEY( "start" ), LFUNCVAL( tmr_start ) }, { LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) }, -#ifdef ENABLE_TIMER_SUSPEND +#ifdef TIMER_SUSPEND_ENABLE { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, { LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, @@ -492,15 +433,13 @@ static const LUA_REG_TYPE tmr_map[] = { { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) }, { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) }, { LSTRKEY( "create" ), LFUNCVAL( tmr_create ) }, -#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG) - { LSTRKEY( "debug" ), LROVAL( tmr_dbg_map ) }, -#endif { LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) }, { LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) }, { LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) }, { LNILKEY, LNILVAL } }; +#include "pm/swtimer.h" int luaopen_tmr( lua_State *L ){ int i; @@ -510,16 +449,23 @@ int luaopen_tmr( lua_State *L ){ alarm_timers[i].lua_ref = LUA_NOREF; alarm_timers[i].self_ref = LUA_REFNIL; alarm_timers[i].mode = TIMER_MODE_OFF; - //improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call. - ets_timer_disarm(&alarm_timers[i].os); + os_timer_disarm(&alarm_timers[i].os); } last_rtc_time=system_get_rtc_time(); // Right now is time 0 last_rtc_time_us=0; - //improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call. - ets_timer_disarm(&rtc_timer); + os_timer_disarm(&rtc_timer); os_timer_setfn(&rtc_timer, rtc_callback, NULL); os_timer_arm(&rtc_timer, 1000, 1); + + SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME); + //The function rtc_callback calls the a function that calibrates the SoftRTC for drift in the esp8266's clock. + //My guess: after the duration of light_sleep there's bound to be some drift in the clock, so a calibration is due. + SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME); + //The function alarm_timer_common handles timers created by the developer via tmr.create(). + //No reason not to resume the timers, so resume em'. + + return 0; } diff --git a/app/modules/wifi.c b/app/modules/wifi.c index 426fa11a..8ff1db39 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -429,7 +429,7 @@ static int wifi_setmaxtxpower( lua_State* L ) #ifdef PMSLEEP_ENABLE /* Begin WiFi suspend functions*/ -#include "pmSleep.h" +#include static int wifi_resume_cb_ref = LUA_NOREF; // Holds resume callback reference static int wifi_suspend_cb_ref = LUA_NOREF; // Holds suspend callback reference @@ -511,6 +511,19 @@ static int wifi_resume(lua_State* L) } /* End WiFi suspend functions*/ +#else +static char *susp_note_str = "\n The option \"pmsleep_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n"; +static char *susp_unavailable_str = "wifi.suspend is unavailable"; + +static int wifi_suspend(lua_State* L){ + c_sprintf("%s", susp_note_str); + return luaL_error(L, susp_unavailable_str); +} + +static int wifi_resume(lua_State* L){ + c_sprintf("%s", susp_note_str); + return luaL_error(L, susp_unavailable_str); +} #endif // Lua: wifi.nullmodesleep() @@ -963,7 +976,7 @@ static int wifi_station_config( lua_State* L ) lua_State* L_temp = NULL; - lua_getfield(L, 1, "connected_cb"); + lua_getfield(L, 1, "connect_cb"); if (!lua_isnil(L, -1)) { if (lua_isfunction(L, -1)) @@ -976,12 +989,12 @@ static int wifi_station_config( lua_State* L ) } else { - return luaL_argerror(L, 1, "connected_cb:not function"); + return luaL_argerror(L, 1, "connect_cb:not function"); } } lua_pop(L, 1); - lua_getfield(L, 1, "disconnected_cb"); + lua_getfield(L, 1, "disconnect_cb"); if (!lua_isnil(L, -1)) { if (lua_isfunction(L, -1)) @@ -994,7 +1007,7 @@ static int wifi_station_config( lua_State* L ) } else { - return luaL_argerror(L, 1, "disconnected_cb:not function"); + return luaL_argerror(L, 1, "disconnect_cb:not function"); } } lua_pop(L, 1); @@ -1910,10 +1923,8 @@ static const LUA_REG_TYPE wifi_map[] = { { LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) }, { LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) }, { LSTRKEY( "setmaxtxpower" ), LFUNCVAL( wifi_setmaxtxpower ) }, -#ifdef PMSLEEP_ENABLE { LSTRKEY( "suspend" ), LFUNCVAL( wifi_suspend ) }, { LSTRKEY( "resume" ), LFUNCVAL( wifi_resume ) }, -#endif { LSTRKEY( "nullmodesleep" ), LFUNCVAL( wifi_null_mode_auto_sleep ) }, #ifdef WIFI_SMART_ENABLE { LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) }, diff --git a/app/modules/ws2812_effects.c b/app/modules/ws2812_effects.c index f2281b87..17b7306e 100644 --- a/app/modules/ws2812_effects.c +++ b/app/modules/ws2812_effects.c @@ -8,7 +8,7 @@ #include "user_interface.h" #include "driver/uart.h" #include "osapi.h" -#include "swTimer/swTimer.h" +#include "pm/swtimer.h" #include "ws2812.h" #include "color_utils.h" diff --git a/app/net/nodemcu_mdns.c b/app/net/nodemcu_mdns.c index ea743888..4efee2dc 100644 --- a/app/net/nodemcu_mdns.c +++ b/app/net/nodemcu_mdns.c @@ -1056,6 +1056,7 @@ mdns_dup_info(const struct nodemcu_mdns_info *info) { return result; } +#include "pm/swtimer.h" /** * Initialize the resolver: set up the UDP pcb and configure the default server * (NEW IP). @@ -1130,6 +1131,9 @@ nodemcu_mdns_init(struct nodemcu_mdns_info *info) { //MDNS_DBG("About to start timer\n"); os_timer_disarm(&mdns_timer); os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info); + SWTIMER_REG_CB(mdns_reg, SWTIMER_RESUME); + //the function mdns_reg registers the mdns device on the network + //My guess: Since wifi connection is restored after waking from light_sleep, the related timer would have no problem resuming it's normal function. os_timer_arm(&mdns_timer, 1000 * 280, 1); /* kick off the first one right away */ mdns_reg_handler_restart(); diff --git a/app/pm/pmSleep.c b/app/pm/pmSleep.c index ad8c75b9..d1774fc1 100644 --- a/app/pm/pmSleep.c +++ b/app/pm/pmSleep.c @@ -1,8 +1,10 @@ -#include "pmSleep.h" +#include #ifdef PMSLEEP_ENABLE #define STRINGIFY_VAL(x) #x #define STRINGIFY(x) STRINGIFY_VAL(x) +//TODO: figure out why timed light_sleep doesn't work + //holds duration error string //uint32 PMSLEEP_SLEEP_MAX_TIME=FPM_SLEEP_MAX_TIME-1; const char *PMSLEEP_DURATION_ERR_STR="duration: 0 or "STRINGIFY(PMSLEEP_SLEEP_MIN_TIME)"-"STRINGIFY(PMSLEEP_SLEEP_MAX_TIME)" us"; @@ -28,17 +30,18 @@ static void wifi_suspended_timer_cb(int arg); /* INTERNAL FUNCTIONS */ -#include "swTimer/swTimer.h" static void suspend_all_timers(void){ -#ifdef ENABLE_TIMER_SUSPEND - swtmr_suspend(NULL); +#ifdef TIMER_SUSPEND_ENABLE + extern void swtmr_suspend_timers(); + swtmr_suspend_timers(); #endif return; } static void resume_all_timers(void){ -#ifdef ENABLE_TIMER_SUSPEND - swtmr_resume(NULL); +#ifdef TIMER_SUSPEND_ENABLE + extern void swtmr_resume_timers(); + swtmr_resume_timers(); #endif return; } @@ -49,7 +52,7 @@ static void null_mode_check_timer_cb(void* arg){ if(current_config.sleep_mode == LIGHT_SLEEP_T){ if((READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT<= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) || - (Linteger == 0)), table_idx, PMSLEEP_DURATION_ERR_STR); - cfg->sleep_duration = (uint32)Linteger; // Get suspend duration + if( cfg->sleep_mode == MODEM_SLEEP_T ){ //WiFi suspend + lua_getfield(L, table_idx, "duration"); + if( !lua_isnil(L, -1) ){ /* found? */ + if( lua_isnumber(L, -1) ){ + lua_Integer Linteger=luaL_checkinteger(L, -1); + luaL_argcheck(L,(((Linteger >= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) || + (Linteger == 0)), table_idx, PMSLEEP_DURATION_ERR_STR); + cfg->sleep_duration = (uint32)Linteger; // Get suspend duration + } + else{ + return luaL_argerror( L, table_idx, "duration: must be number" ); + } } else{ - return luaL_argerror( L, table_idx, "duration: must be number" ); + return luaL_argerror( L, table_idx, PMSLEEP_DURATION_ERR_STR ); } - } - else{ - return luaL_argerror( L, table_idx, PMSLEEP_DURATION_ERR_STR ); - } - lua_pop(L, 1); + lua_pop(L, 1); - if( cfg->sleep_mode == MODEM_SLEEP_T ){ //WiFi suspend lua_getfield(L, table_idx, "suspend_cb"); if( !lua_isnil(L, -1) ){ /* found? */ if( lua_isfunction(L, -1) ){ @@ -204,7 +209,7 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, lua_pop(L, 1); } else if (cfg->sleep_mode == LIGHT_SLEEP_T){ //CPU suspend -#ifdef ENABLE_TIMER_SUSPEND +#ifdef TIMER_SUSPEND_ENABLE lua_getfield(L, table_idx, "wake_pin"); if( !lua_isnil(L, -1) ){ /* found? */ if( lua_isnumber(L, -1) ){ @@ -216,9 +221,11 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, return luaL_argerror( L, table_idx, "wake_pin: must be number" ); } } - else if(cfg->sleep_duration == 0){ - return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" ); - } + else{ + return luaL_argerror( L, table_idx, "wake_pin: must specify pin" ); +// else if(cfg->sleep_duration == 0){ +// return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" ); + } lua_pop(L, 1); lua_getfield(L, table_idx, "int_type"); @@ -300,7 +307,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ PMSLEEP_DBG("START"); lua_State* L = lua_getstate(); -#ifndef ENABLE_TIMER_SUSPEND +#ifndef TIMER_SUSPEND_ENABLE if(cfg->sleep_mode == LIGHT_SLEEP_T){ luaL_error(L, "timer suspend API is disabled, light sleep unavailable"); return; @@ -336,7 +343,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ wifi_fpm_open(); // Enable force sleep API if (cfg->sleep_mode == LIGHT_SLEEP_T){ -#ifdef ENABLE_TIMER_SUSPEND +#ifdef TIMER_SUSPEND_ENABLE if(platform_gpio_exists(cfg->wake_pin) && cfg->wake_pin > 0){ PMSLEEP_DBG("Wake-up pin is %d\t interrupt type is %d", cfg->wake_pin, cfg->int_type); @@ -366,10 +373,11 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ c_memcpy(¤t_config, cfg, sizeof(pmSleep_param_t)); PMSLEEP_DBG("sleep duration is %d", current_config.sleep_duration); - //this timer intentionally bypasses the swtimer timer registration process - ets_timer_disarm(&null_mode_check_timer); - ets_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false); - ets_timer_arm_new(&null_mode_check_timer, 1, 1, 1); + os_timer_disarm(&null_mode_check_timer); + os_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false); + //The function null_mode_check_timer_cb checks that the esp8266 has successfully changed the opmode to NULL_MODE prior to entering LIGHT_SLEEP + //This callback doesn't need to be registered with SWTIMER_REG_CB since the timer will have terminated before entering LIGHT_SLEEP + os_timer_arm(&null_mode_check_timer, 1, 1); } else{ PMSLEEP_ERR("opmode change fail"); diff --git a/app/pm/swtimer.c b/app/pm/swtimer.c new file mode 100644 index 00000000..bedbf954 --- /dev/null +++ b/app/pm/swtimer.c @@ -0,0 +1,545 @@ +/* swTimer.c SDK timer suspend API + * + * SDK software timer API info: + * + * The SDK software timer uses a linked list called `os_timer_t* timer_list` to keep track of + * all currently armed timers. + * + * The SDK software timer API executes in a task. The priority of this task in relation to the + * application level tasks is unknown (at time of writing). + * + * + * To determine when a timer's callback should be executed, the respective timer's `timer_expire` + * variable is compared to the hardware counter(FRC2), then, if the timer's `timer_expire` is + * less than the current FRC2 count, the timer's callback is fired. + * + * The timers in this list are organized in an ascending order starting with the timer + * with the lowest timer_expire. + * + * When a timer expires that has a timer_period greater than 0, timer_expire is changed to + * current FRC2 + timer_period, then the timer is inserted back in to the list in the correct position. + * + * when using millisecond(default) timers, FRC2 resolution is 312.5 ticks per millisecond. + * + * + * TIMER SUSPEND API INFO: + * + * Timer suspension is achieved by first finding any non-SDK timers by comparing the timer function callback pointer + * of each timer in "timer_list" to a list of registered timer callback pointers stored in the Lua registry. + * If a timer with a corresponding registered callback pointer is found, the timer's timer_expire field is is compared + * to the current FRC2 count and the difference is saved along with the other timer parameters to temporary variables. + * The timer is then disarmed and the parameters are copied back, the timer pointer is then + * added to a separate linked list of which the head pointer is stored as a lightuserdata in the lua registry. + * + * Resuming the timers is achieved by first retrieving the lightuserdata holding the suspended timer list head pointer. + * Then, starting with the beginning of the list the current FRC2 count is added back to the timer's timer_expire, then + * the timer is manually added back to "timer_list" in an ascending order. + * Once there are no more suspended timers, the function returns + * + * + */#include "module.h" +#include "lauxlib.h" +#include "platform.h" + +#include "user_interface.h" +#include "user_modules.h" + +#include "c_string.h" +#include "c_stdlib.h" +#include "ctype.h" + +#include "c_types.h" + +//#define SWTMR_DEBUG +#if !defined(SWTMR_DBG) && defined(LUA_USE_MODULES_SWTMR_DBG) + #define SWTMR_DEBUG +#endif + +//this section specifies which lua registry to use. LUA_GLOBALSINDEX or LUA_REGISTRYINDEX +#ifdef SWTMR_DEBUG +#define SWTMR_DBG(fmt, ...) c_printf("\n SWTMR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__) +#define L_REGISTRY LUA_GLOBALSINDEX +#define CB_LIST_STR "timer_cb_ptrs" +#define SUSP_LIST_STR "suspended_tmr_LL_head" +#else +#define SWTMR_DBG(...) +#define L_REGISTRY LUA_REGISTRYINDEX +#define CB_LIST_STR "cb" +#define SUSP_LIST_STR "st" +#endif + + +typedef struct tmr_cb_queue{ + os_timer_func_t *tmr_cb_ptr; + uint8 suspend_policy; + struct tmr_cb_queue * next; +}tmr_cb_queue_t; + +typedef struct cb_registry_item{ + os_timer_func_t *tmr_cb_ptr; + uint8 suspend_policy; +}cb_registry_item_t; + + +/* Internal variables */ +static tmr_cb_queue_t* register_queue = NULL; +static task_handle_t cb_register_task_id = NULL; //variable to hold task id for task handler(process_cb_register_queue) + +/* Function declarations */ +//void swtmr_cb_register(void* timer_cb_ptr, uint8 resume_policy); +static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy); +static void process_cb_register_queue(task_param_t param, uint8 priority); + + +#ifdef SWTMR_DEBUG +#define push_swtmr_registry_key(L) lua_pushstring(L, "SWTMR_registry_key") +#else +#define push_swtmr_registry_key(L) lua_pushlightuserdata(L, ®ister_queue); +#endif + +#include + +void swtmr_suspend_timers(){ + lua_State* L = lua_getstate(); + + //get swtimer table + push_swtmr_registry_key(L); + lua_rawget(L, L_REGISTRY); + + //get cb_list table + lua_pushstring(L, CB_LIST_STR); + lua_rawget(L, -2); + + //check for existence of the swtimer table and the cb_list table, return if not found + if(!lua_istable(L, -2) || !lua_istable(L, -1)){ + // not necessarily an error maybe there are legitimately no timers to suspend + lua_pop(L, 2); + return; + } + + os_timer_t* suspended_timer_list_head = NULL; + os_timer_t* suspended_timer_list_tail = NULL; + + //get suspended_timer_list table + lua_pushstring(L, SUSP_LIST_STR); + lua_rawget(L, -3); + + //if suspended_timer_list exists, find tail of list + if(lua_isuserdata(L, -1)){ + suspended_timer_list_head = suspended_timer_list_tail = lua_touserdata(L, -1); + while(suspended_timer_list_tail->timer_next != NULL){ + suspended_timer_list_tail = suspended_timer_list_tail->timer_next; + } + } + + lua_pop(L, 1); + + //get length of lua table containing the callback pointers + size_t registered_cb_qty = lua_objlen(L, -1); + + //allocate a temporary array to hold the list of callback pointers + cb_registry_item_t** cb_reg_array = c_zalloc(sizeof(cb_registry_item_t*)*registered_cb_qty); + if(!cb_reg_array){ + luaL_error(L, "%s: unable to suspend timers, out of memory!", __func__); + return; + } + uint8 index = 0; + + //convert lua table cb_list to c array + lua_pushnil(L); + while(lua_next(L, -2) != 0){ + if(lua_isuserdata(L, -1)){ + cb_reg_array[index] = lua_touserdata(L, -1); + } + lua_pop(L, 1); + index++; + } + + //the cb_list table is no longer needed, pop it from the stack + lua_pop(L, 1); + + volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); + + os_timer_t* timer_ptr = timer_list; + + uint32 expire_temp = 0; + uint32 period_temp = 0; + void* arg_temp = NULL; + + /* In this section, the SDK's timer_list is traversed to find any timers that have a registered callback pointer. + * If a registered callback is found, the timer is suspended by saving the difference + * between frc2_count and timer_expire then the timer is disarmed and placed into suspended_timer_list + * so it can later be resumed. + */ + while(timer_ptr != NULL){ + os_timer_t* next_timer = (os_timer_t*)0xffffffff; + for(int i = 0; i < registered_cb_qty; i++){ + if(timer_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){ + + //current timer will be suspended, next timer's pointer will be needed to continue processing timer_list + next_timer = timer_ptr->timer_next; + + //store timer parameters temporarily so the timer can be disarmed + if(timer_ptr->timer_expire < frc2_count) + expire_temp = 2; // 16 us in ticks (1 tick = ~3.2 us) (arbitrarily chosen value) + else + expire_temp = timer_ptr->timer_expire - frc2_count; + period_temp = timer_ptr->timer_period; + arg_temp = timer_ptr->timer_arg; + + if(timer_ptr->timer_period == 0 && cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){ + SWTMR_DBG("Warning: suspend_policy(RESTART) is not compatible with single-shot timer(%p), changing suspend_policy to (RESUME)", timer_ptr); + cb_reg_array[i]->suspend_policy = SWTIMER_RESUME; + } + + //remove the timer from timer_list so we don't have to. + os_timer_disarm(timer_ptr); + + timer_ptr->timer_next = NULL; + + //this section determines timer behavior on resume + if(cb_reg_array[i]->suspend_policy == SWTIMER_DROP){ + SWTMR_DBG("timer(%p) was disarmed and will not be resumed", timer_ptr); + } + else if(cb_reg_array[i]->suspend_policy == SWTIMER_IMMEDIATE){ + timer_ptr->timer_expire = 1; + SWTMR_DBG("timer(%p) will fire immediately on resume", timer_ptr); + } + else if(cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){ + timer_ptr->timer_expire = period_temp; + SWTMR_DBG("timer(%p) will be restarted on resume", timer_ptr); + } + else{ + timer_ptr->timer_expire = expire_temp; + SWTMR_DBG("timer(%p) will be resumed with remaining time", timer_ptr); + } + + if(cb_reg_array[i]->suspend_policy != SWTIMER_DROP){ + timer_ptr->timer_period = period_temp; + timer_ptr->timer_func = cb_reg_array[i]->tmr_cb_ptr; + timer_ptr->timer_arg = arg_temp; + + //add timer to suspended_timer_list + if(suspended_timer_list_head == NULL){ + suspended_timer_list_head = timer_ptr; + suspended_timer_list_tail = timer_ptr; + } + else{ + suspended_timer_list_tail->timer_next = timer_ptr; + suspended_timer_list_tail = timer_ptr; + } + } + } + } + + //if timer was suspended, timer_ptr->timer_next is invalid, use next_timer instead. + if(next_timer != (os_timer_t*)0xffffffff){ + timer_ptr = next_timer; + } + else{ + timer_ptr = timer_ptr->timer_next; + } + } + + //tmr_cb_ptr_array is no longer needed. + c_free(cb_reg_array); + + //add suspended_timer_list pointer to swtimer table. + lua_pushstring(L, SUSP_LIST_STR); + lua_pushlightuserdata(L, suspended_timer_list_head); + lua_rawset(L, -3); + + //pop swtimer table from stack + lua_pop(L, 1); + return; +} + +void swtmr_resume_timers(){ + lua_State* L = lua_getstate(); + + //get swtimer table + push_swtmr_registry_key(L); + lua_rawget(L, L_REGISTRY); + + //get suspended_timer_list lightuserdata + lua_pushstring(L, SUSP_LIST_STR); + lua_rawget(L, -2); + + //check for existence of swtimer table and the suspended_timer_list pointer userdata, return if not found + if(!lua_istable(L, -2) || !lua_isuserdata(L, -1)){ + // not necessarily an error maybe there are legitimately no timers to resume + lua_pop(L, 2); + return; + } + + os_timer_t* suspended_timer_list_ptr = lua_touserdata(L, -1); + lua_pop(L, 1); //pop suspended timer list userdata from stack + + //since timers will be resumed, the suspended_timer_list lightuserdata can be cleared from swtimer table + lua_pushstring(L, SUSP_LIST_STR); + lua_pushnil(L); + lua_rawset(L, -3); + + + lua_pop(L, 1); //pop swtimer table from stack + + volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); + + //this section does the actual resuming of the suspended timer(s) + while(suspended_timer_list_ptr != NULL){ + os_timer_t* timer_list_ptr = timer_list; + + //the pointer to next suspended timer must be saved, the current suspended timer will be removed from the list + os_timer_t* next_suspended_timer_ptr = suspended_timer_list_ptr->timer_next; + + suspended_timer_list_ptr->timer_expire += frc2_count; + + //traverse timer_list to determine where to insert suspended timer + while(timer_list_ptr != NULL){ + if(suspended_timer_list_ptr->timer_expire > timer_list_ptr->timer_expire){ + if(timer_list_ptr->timer_next != NULL){ + //current timer is not at tail of timer_list + if(suspended_timer_list_ptr->timer_expire < timer_list_ptr->timer_next->timer_expire){ + //insert suspended timer between current timer and next timer + suspended_timer_list_ptr->timer_next = timer_list_ptr->timer_next; + timer_list_ptr->timer_next = suspended_timer_list_ptr; + break; //timer resumed exit while loop + } + else{ + //suspended timer expire is larger than next timer + } + } + else{ + //current timer is at tail of timer_list and suspended timer expire is greater then current timer + //append timer to end of timer_list + timer_list_ptr->timer_next = suspended_timer_list_ptr; + suspended_timer_list_ptr->timer_next = NULL; + break; //timer resumed exit while loop + } + } + else if(timer_list_ptr == timer_list){ + //insert timer at head of list + suspended_timer_list_ptr->timer_next = timer_list_ptr; + timer_list = timer_list_ptr = suspended_timer_list_ptr; + break; //timer resumed exit while loop + } + //suspended timer expire is larger than next timer + //timer not resumed, next timer in timer_list + timer_list_ptr = timer_list_ptr->timer_next; + } + //timer was resumed, next suspended timer + suspended_timer_list_ptr = next_suspended_timer_ptr; + } + return; +} + +//this function registers a timer callback pointer in a lua table +void swtmr_cb_register(void* timer_cb_ptr, uint8 suspend_policy){ + lua_State* L = lua_getstate(); + if(!L){ + //Lua has not started yet, therefore L_REGISTRY is not available. + //add timer cb to queue for later processing after Lua has started + add_to_reg_queue(timer_cb_ptr, suspend_policy); + return; + } + if(timer_cb_ptr){ + size_t cb_list_last_idx = 0; + + push_swtmr_registry_key(L); + lua_rawget(L, L_REGISTRY); + + if(!lua_istable(L, -1)){ + //swtmr does not exist, create and add to registry + lua_pop(L, 1); + lua_newtable(L);//push new table for swtmr.timer_cb_list + // add swtimer table to L_REGISTRY + push_swtmr_registry_key(L); + lua_pushvalue(L, -2); + lua_rawset(L, L_REGISTRY); + } + + lua_pushstring(L, CB_LIST_STR); + lua_rawget(L, -2); + + if(lua_istable(L, -1)){ + //cb_list exists, get length of list + cb_list_last_idx = lua_objlen(L, -1); + } + else{ + //cb_list does not exist in swtmr, create and add to swtmr + lua_pop(L, 1);// pop nil value from stack + lua_newtable(L);//create new table for swtmr.timer_cb_list + lua_pushstring(L, CB_LIST_STR); //push name for the new table onto the stack + lua_pushvalue(L, -2); //push table to top of stack + lua_rawset(L, -4); //pop table and name from stack and register in swtmr + } + + //append new timer cb ptr to table + lua_pushnumber(L, cb_list_last_idx+1); + cb_registry_item_t* reg_item = lua_newuserdata(L, sizeof(cb_registry_item_t)); + reg_item->tmr_cb_ptr = timer_cb_ptr; + reg_item->suspend_policy = suspend_policy; + lua_rawset(L, -3); + + //clear items pushed onto stack by this function + lua_pop(L, 2); + } + return; +} + +//this function adds the timer cb ptr to a queue for later registration after lua has started +static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy){ + if(!timer_cb_ptr) + return; + tmr_cb_queue_t* queue_temp = c_zalloc(sizeof(tmr_cb_queue_t)); + if(!queue_temp){ + //it's boot time currently and we're already out of memory, something is very wrong... + c_printf("\n\t%s:out of memory, system halted!\n", __FUNCTION__); + while(1) + system_soft_wdt_feed(); + } + queue_temp->tmr_cb_ptr = timer_cb_ptr; + queue_temp->suspend_policy = suspend_policy; + queue_temp->next = NULL; + + if(register_queue == NULL){ + register_queue = queue_temp; + } + else{ + tmr_cb_queue_t* queue_ptr = register_queue; + while(queue_ptr->next != NULL){ + queue_ptr = queue_ptr->next; + } + queue_ptr->next = queue_temp; + } + if(!cb_register_task_id){ + cb_register_task_id = task_get_id(process_cb_register_queue);//get task id from task interface + task_post_low(cb_register_task_id, false); //post task to process next item in queue + } + return; +} + +static void process_cb_register_queue(task_param_t param, uint8 priority) +{ + if(!lua_getstate()){ + SWTMR_DBG("L== NULL, Lua not yet started! posting task"); + task_post_low(cb_register_task_id, false); //post task to process next item in queue + return; + } + while(register_queue != NULL){ + tmr_cb_queue_t* register_queue_ptr = register_queue; + void* cb_ptr_tmp = register_queue_ptr->tmr_cb_ptr; + swtmr_cb_register(cb_ptr_tmp, register_queue_ptr->suspend_policy); + register_queue = register_queue->next; + c_free(register_queue_ptr); + } + return; +} + +#ifdef SWTMR_DEBUG +int print_timer_list(lua_State* L){ + push_swtmr_registry_key(L); + lua_rawget(L, L_REGISTRY); + lua_pushstring(L, CB_LIST_STR); + lua_rawget(L, -2); + if(!lua_istable(L, -2) || !lua_istable(L, -1)){ + lua_pop(L, 2); + return 0; + } + os_timer_t* suspended_timer_list_head = NULL; + os_timer_t* suspended_timer_list_tail = NULL; + lua_pushstring(L, SUSP_LIST_STR); + lua_rawget(L, -3); + if(lua_isuserdata(L, -1)){ + suspended_timer_list_head = suspended_timer_list_tail = lua_touserdata(L, -1); + while(suspended_timer_list_tail->timer_next != NULL){ + suspended_timer_list_tail = suspended_timer_list_tail->timer_next; + } + } + lua_pop(L, 1); + size_t registered_cb_qty = lua_objlen(L, -1); + cb_registry_item_t** cb_reg_array = c_zalloc(sizeof(cb_registry_item_t*)*registered_cb_qty); + if(!cb_reg_array){ + luaL_error(L, "%s: unable to suspend timers, out of memory!", __func__); + return 0; + } + uint8 index = 0; + lua_pushnil(L); + while(lua_next(L, -2) != 0){ + if(lua_isuserdata(L, -1)){ + cb_reg_array[index] = lua_touserdata(L, -1); + } + lua_pop(L, 1); + index++; + } + lua_pop(L, 1); + + + os_timer_t* timer_list_ptr = timer_list; + c_printf("\n\tCurrent FRC2: %u\n", RTC_REG_READ(FRC2_COUNT_ADDRESS)); + c_printf("\ttimer_list:\n"); + while(timer_list_ptr != NULL){ + bool registered_flag = FALSE; + for(int i=0; i < registered_cb_qty; i++){ + if(timer_list_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){ + registered_flag = TRUE; + break; + } + } + c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\t%s\n", + timer_list_ptr, timer_list_ptr->timer_func, timer_list_ptr->timer_expire, timer_list_ptr->timer_period, timer_list_ptr->timer_next, registered_flag ? "Registered" : ""); + timer_list_ptr = timer_list_ptr->timer_next; + } + + c_free(cb_reg_array); + lua_pop(L, 1); + + return 0; +} + +int print_susp_timer_list(lua_State* L){ + push_swtmr_registry_key(L); + lua_rawget(L, L_REGISTRY); + + if(!lua_istable(L, -1)){ + return luaL_error(L, "swtmr table not found!"); + } + + lua_pushstring(L, SUSP_LIST_STR); + lua_rawget(L, -2); + + if(!lua_isuserdata(L, -1)){ + return luaL_error(L, "swtmr.suspended_list userdata not found!"); + } + + os_timer_t* susp_timer_list_ptr = lua_touserdata(L, -1); + c_printf("\n\tsuspended_timer_list:\n"); + while(susp_timer_list_ptr != NULL){ + c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\n",susp_timer_list_ptr, susp_timer_list_ptr->timer_func, susp_timer_list_ptr->timer_expire, susp_timer_list_ptr->timer_period, susp_timer_list_ptr->timer_next); + susp_timer_list_ptr = susp_timer_list_ptr->timer_next; + } + return 0; +} + +int suspend_timers_lua(lua_State* L){ + swtmr_suspend_timers(); + return 0; +} + +int resume_timers_lua(lua_State* L){ + swtmr_resume_timers(); + return 0; +} + +static const LUA_REG_TYPE test_swtimer_debug_map[] = { + { LSTRKEY( "timer_list" ), LFUNCVAL( print_timer_list ) }, + { LSTRKEY( "susp_timer_list" ), LFUNCVAL( print_susp_timer_list ) }, + { LSTRKEY( "suspend" ), LFUNCVAL( suspend_timers_lua ) }, + { LSTRKEY( "resume" ), LFUNCVAL( resume_timers_lua ) }, + { LNILKEY, LNILVAL } +}; + +NODEMCU_MODULE(SWTMR_DBG, "SWTMR_DBG", test_swtimer_debug_map, NULL); + +#endif + diff --git a/app/smart/smart.c b/app/smart/smart.c index 2b7a906c..aebece08 100644 --- a/app/smart/smart.c +++ b/app/smart/smart.c @@ -3,6 +3,7 @@ #include "c_string.h" #include "user_interface.h" #include "smart.h" +#include "pm/swtimer.h" #define ADDR_MAP_NUM 10 @@ -500,6 +501,9 @@ void smart_end(){ os_timer_disarm(&smart_timer); os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)1); + SWTIMER_REG_CB(station_check_connect, SWTIMER_RESUME); + //the function station_check_connect continues the Smart config process and fires the developers callback upon successful connection to the access point. + //If this function manages to get suspended, I think it would be fine to resume the timer. os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat } } @@ -672,6 +676,9 @@ void smart_begin(int chnl, smart_succeed s, void *arg){ wifi_set_promiscuous_rx_cb(detect); os_timer_disarm(&smart_timer); os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL); + SWTIMER_REG_CB(smart_next_channel, SWTIMER_RESUME); + //smart_next_channel switches the wifi channel + //I don't see a problem with resuming this timer os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0); // no repeat if(s){ @@ -717,5 +724,6 @@ void station_check_connect(bool smart){ } os_timer_disarm(&smart_timer); os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)(int)smart); + //this function was already registered in the function smart_end. os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat } diff --git a/app/swTimer/Makefile b/app/swTimer/Makefile deleted file mode 100644 index eaa132c9..00000000 --- a/app/swTimer/Makefile +++ /dev/null @@ -1,52 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR -GEN_LIBS = libswtimer.a -endif - -STD_CFLAGS=-std=gnu11 -Wimplicit - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -INCLUDES += -I ./ -INCLUDES += -I ./include -INCLUDES += -I ../include -INCLUDES += -I ../../include -INCLUDES += -I ../lua -INCLUDES += -I ../platform -INCLUDES += -I ../libc - -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/app/swTimer/swTimer.c b/app/swTimer/swTimer.c deleted file mode 100644 index 9c86c4aa..00000000 --- a/app/swTimer/swTimer.c +++ /dev/null @@ -1,632 +0,0 @@ -/* swTimer.c SDK timer suspend API - * - * SDK software timer API info: - * - * The SDK software timer uses a linked list called `os_timer_t* timer_list` to keep track of - * all currently armed timers. - * - * The SDK software timer API executes in a task. The priority of this task in relation to the - * application level tasks is unknown (at time of writing). - * - * - * To determine when a timer's callback should be executed, the respective timer's `timer_expire` - * variable is compared to the hardware counter(FRC2), then, if the timer's `timer_expire` is - * less than the current FRC2 count, the timer's callback is fired. - * - * The timers in this list are organized in an ascending order starting with the timer - * with the lowest timer_expire. - * - * When a timer expires that has a timer_period greater than 0, timer_expire is changed to - * current FRC2 + timer_period, then the timer is inserted back in to the list in the correct position. - * - * when using millisecond(default) timers, FRC2 resolution is 312.5 ticks per millisecond. - * - * - * TIMER SUSPEND API: - * - * Timer registry: - * void sw_timer_register(void* timer_ptr); - * - Adds timers to the timer registry by adding it to a queue that is later - * processed by timer_register_task that performs the registry maintenance - * - * void sw_timer_unregister(void* timer_ptr); - * - Removes timers from the timer registry by adding it to a queue that is later - * processed by timer_unregister_task that performs the registry maintenance - * - * - * int sw_timer_suspend(os_timer_t* timer_ptr); - * - Suspend a single active timer or suspend all active timers. - * - if no timer pointer is provided, timer_ptr == NULL, then all currently active timers will be suspended. - * - * int sw_timer_resume(os_timer_t* timer_ptr); - * - Resume a single suspended timer or resume all suspended timers. - * - if no timer pointer is provided, timer_ptr == NULL, then all currently suspended timers will be resumed. - * - * - * - */ -#include "swTimer/swTimer.h" -#include "c_stdio.h" -#include "misc/dynarr.h" -#include "task/task.h" - -#ifdef ENABLE_TIMER_SUSPEND - -/* Settings */ -#define TIMER_REGISTRY_INITIAL_SIZE 10 -#ifdef USE_SWTMR_ERROR_STRINGS -static const char* SWTMR_ERROR_STRINGS[]={ - [SWTMR_MALLOC_FAIL] = "Out of memory!", - [SWTMR_TIMER_NOT_ARMED] = "Timer is not armed", -// [SWTMR_NULL_PTR] = "A NULL pointer was passed to timer suspend api", - [SWTMR_REGISTRY_NO_REGISTERED_TIMERS] = "No timers in registry", -// [SWTMR_SUSPEND_ARRAY_INITIALIZATION_FAILED] = "Suspend array init fail", -// [SWTMR_SUSPEND_ARRAY_ADD_FAILED] = "Unable to add suspended timer to array", -// [SWTMR_SUSPEND_ARRAY_REMOVE_FAILED] = "Unable to remove suspended timer from array", - [SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED] = "Already suspended", - [SWTMR_SUSPEND_TIMER_ALREADY_REARMED] = "Already been re-armed", - [SWTMR_SUSPEND_NO_SUSPENDED_TIMERS] = "No suspended timers", - [SWTMR_SUSPEND_TIMER_NOT_SUSPENDED] = "Not suspended", - -}; -#endif - -/* Private Function Declarations */ -static inline bool timer_armed_check(os_timer_t* timer_ptr); -static inline int timer_do_suspend(os_timer_t* timer_ptr); -static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr); -static void timer_register_task(task_param_t param, uint8 priority); -static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr); -static inline void timer_registry_remove_unarmed(void); -static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr); -static void timer_unregister_task(task_param_t param, uint8 priority); - -/* Private Variable Definitions */ - static task_handle_t timer_reg_task_id = false; - static task_handle_t timer_unreg_task_id = false; - - static dynarr_t timer_registry = {0}; - static dynarr_t suspended_timers = {0}; - - typedef struct registry_queue{ - struct registry_queue* next; - os_timer_t* timer_ptr; - }registry_queue_t; - - static registry_queue_t* register_queue = NULL; - static registry_queue_t* unregister_queue = NULL; - -/* Private Function Definitions */ - -//NOTE: Interrupts are temporarily blocked during the execution of this function -static inline bool timer_armed_check(os_timer_t* timer_ptr){ - bool retval = FALSE; - - // we are messing around with the SDK timer structure here, may not be necessary, better safe than sorry though. - ETS_INTR_LOCK(); - - os_timer_t* timer_list_ptr = timer_list; //get head node pointer of timer_list - - //if present find timer_ptr in timer_list rand return result - while(timer_list_ptr != NULL){ - if(timer_list_ptr == timer_ptr){ - retval = TRUE; - break; - } - timer_list_ptr = timer_list_ptr->timer_next; - } - - //we are done with timer_list, it is now safe to unlock interrupts - ETS_INTR_UNLOCK(); - - //return value - return retval; -} - -static inline int timer_do_suspend(os_timer_t* timer_ptr){ - if(timer_ptr == NULL){ - SWTMR_ERR("timer_ptr is invalid"); - return SWTMR_FAIL; - } - - volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); - - if(timer_armed_check(timer_ptr) == FALSE){ - return SWTMR_TIMER_NOT_ARMED; - } - - os_timer_t** suspended_timer_ptr = timer_suspended_check(timer_ptr); - - uint32 expire_temp = 0; - uint32 period_temp = timer_ptr->timer_period; - - if(timer_ptr->timer_expire < frc2_count){ - expire_temp = 5; // 16 us in ticks (1 tick = ~3.2 us) (arbitrarily chosen value) - } - else{ - expire_temp = timer_ptr->timer_expire - frc2_count; - } - - ets_timer_disarm(timer_ptr); - timer_unregister_task((task_param_t)timer_ptr, false); - - timer_ptr->timer_expire = expire_temp; - timer_ptr->timer_period = period_temp; - - if(suspended_timers.data_ptr == NULL){ - if(!dynarr_init(&suspended_timers, 10, sizeof(os_timer_t*))){ - SWTMR_ERR("Suspend array init fail"); - return SWTMR_FAIL; - } - } - - if(suspended_timer_ptr == NULL){ -// return SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED; - if(!dynarr_add(&suspended_timers, &timer_ptr, sizeof(timer_ptr))){ - SWTMR_ERR("Unable to add suspended timer to array"); - return SWTMR_FAIL; - } - } - - return SWTMR_OK; -} - -//NOTE: Interrupts are temporarily blocked during the execution of this function -static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ - if(suspended_timer_ptr == NULL){ - SWTMR_ERR("suspended_timer_ptr is invalid"); - return SWTMR_FAIL; - } - - os_timer_t* timer_list_ptr = NULL; - os_timer_t* resume_timer_ptr = *suspended_timer_ptr; - volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); - - //verify timer has not been rearmed - if(timer_armed_check(resume_timer_ptr) == TRUE){ - SWTMR_DBG("Timer(%p) already rearmed, removing from array", resume_timer_ptr); - if(!dynarr_remove(&suspended_timers, suspended_timer_ptr)){ - SWTMR_ERR("Failed to remove timer from suspend array"); - return SWTMR_FAIL; - } - return SWTMR_OK; - } - - //Prepare timer for resume - resume_timer_ptr->timer_expire += frc2_count; - - timer_register_task((task_param_t)resume_timer_ptr, false); - SWTMR_DBG("Removing timer(%p) from suspend array", resume_timer_ptr); - - //This section performs the actual resume of the suspended timer - - // we are messing around with the SDK timer structure here, may not be necessary, better safe than sorry though. - ETS_INTR_LOCK(); - - timer_list_ptr = timer_list; - - while(timer_list_ptr != NULL){ - if(resume_timer_ptr->timer_expire > timer_list_ptr->timer_expire){ - if(timer_list_ptr->timer_next != NULL){ - if(resume_timer_ptr->timer_expire < timer_list_ptr->timer_next->timer_expire){ - resume_timer_ptr->timer_next = timer_list_ptr->timer_next; - timer_list_ptr->timer_next = resume_timer_ptr; - break; - } - else{ - //next timer in timer_list - } - } - else{ - timer_list_ptr->timer_next = resume_timer_ptr; - resume_timer_ptr->timer_next = NULL; - break; - } - } - else if(timer_list_ptr == timer_list){ - resume_timer_ptr->timer_next=timer_list_ptr; - timer_list = timer_list_ptr = resume_timer_ptr; - break; - } - - timer_list_ptr = timer_list_ptr->timer_next; - } - - //we no longer need to block interrupts - ETS_INTR_UNLOCK(); - - return SWTMR_OK; -} - -static void timer_register_task(task_param_t param, uint8 priority){ - if(timer_registry.data_ptr==NULL){ - if(!dynarr_init(&timer_registry, TIMER_REGISTRY_INITIAL_SIZE, sizeof(os_timer_t*))){ - SWTMR_ERR("timer registry init Fail!"); - return; - } - } - - os_timer_t* timer_ptr = NULL; - - //if a timer pointer is provided, override normal queue processing behavior - if(param != 0){ - timer_ptr = (os_timer_t*)param; - } - else{ - //process an item in the register queue - if(register_queue == NULL){ - /**/SWTMR_ERR("ERROR: REGISTER QUEUE EMPTY"); - return; - } - - registry_queue_t* queue_temp = register_queue; - register_queue = register_queue->next; - - timer_ptr = queue_temp->timer_ptr; - - c_free(queue_temp); - - if(register_queue != NULL){ - SWTMR_DBG("register_queue not empty, posting task"); - task_post_low(timer_reg_task_id, false); - } - } - - os_timer_t** suspended_tmr_ptr = timer_suspended_check(timer_ptr); - if(suspended_tmr_ptr != NULL){ - if(!dynarr_remove(&suspended_timers, suspended_tmr_ptr)){ - SWTMR_ERR("failed to remove %p from suspend registry", suspended_tmr_ptr); - } - SWTMR_DBG("removed timer from suspended timers"); - } - - if(timer_registry_check(timer_ptr) != NULL){ - /**/SWTMR_DBG("timer(%p) found in registry, returning", timer_ptr); - return; - } - - if(!dynarr_add(&timer_registry, &timer_ptr, sizeof(timer_ptr))){ - /**/SWTMR_ERR("Registry append failed"); - return; - } - - return; -} - -static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr){ - if(timer_registry.data_ptr == NULL){ - return NULL; - } - if(timer_registry.used > 0){ - - os_timer_t** timer_registry_array = timer_registry.data_ptr; - - for(uint32 i=0; i < timer_registry.used; i++){ - if(timer_registry_array[i] == timer_ptr){ - /**/SWTMR_DBG("timer(%p) is registered", timer_registry_array[i]); - return &timer_registry_array[i]; - } - } - } - - return NULL; -} - -static inline void timer_registry_remove_unarmed(void){ - if(timer_registry.data_ptr == NULL){ - return; - } - if(timer_registry.used > 0){ - os_timer_t** timer_registry_array = timer_registry.data_ptr; - for(uint32 i=0; i < timer_registry.used; i++){ - if(timer_armed_check(timer_registry_array[i]) == FALSE){ - timer_unregister_task((task_param_t)timer_registry_array[i], false); - } - } - } -} - - -static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr){ - if(suspended_timers.data_ptr == NULL){ - return NULL; - } - if(suspended_timers.used > 0){ - - os_timer_t** suspended_timer_array = suspended_timers.data_ptr; - - for(uint32 i=0; i < suspended_timers.used; i++){ - if(suspended_timer_array[i] == timer_ptr){ - return &suspended_timer_array[i]; - } - } - } - - return NULL; -} - -static void timer_unregister_task(task_param_t param, uint8 priority){ - if(timer_registry.data_ptr == NULL){ - return; - } - os_timer_t* timer_ptr = NULL; - - if(param != false){ - timer_ptr = (os_timer_t*)param; - } - else{ - - if(unregister_queue == NULL) { - SWTMR_ERR("ERROR register queue empty"); - return; - } - registry_queue_t* queue_temp = unregister_queue; - timer_ptr = queue_temp->timer_ptr; - unregister_queue = unregister_queue->next; - c_free(queue_temp); - if(unregister_queue != NULL){ - SWTMR_DBG("unregister_queue not empty, posting task"); - task_post_low(timer_unreg_task_id, false); - } - } - if(timer_armed_check(timer_ptr) == TRUE){ - SWTMR_DBG("%p still armed, can't remove from registry", timer_ptr); - return; - } - - - os_timer_t** registry_ptr = timer_registry_check(timer_ptr); - if(registry_ptr != NULL){ - if(!dynarr_remove(&timer_registry, registry_ptr)){ - - /**/SWTMR_ERR("Failed to remove timer from registry"); - /**/SWTMR_DBG("registry_ptr = %p", registry_ptr); - return; - } - } - else{ - //timer not in registry - } - return; -} - -/* Global Function Definitions */ - -#if defined(SWTMR_DEBUG) - -void swtmr_print_registry(void){ - volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); - uint32 time_till_fire = 0; - uint32 time = system_get_time(); - - timer_registry_remove_unarmed(); - time = system_get_time()-time; - - /**/SWTMR_DBG("registry_remove_unarmed_timers() took %u us", time); - - os_timer_t** timer_array = timer_registry.data_ptr; - - c_printf("\n array used(%u)/size(%u)\ttotal size(bytes)=%u\n FRC2 COUNT %u\n", - timer_registry.used, timer_registry.array_size, timer_registry.array_size * timer_registry.data_size, frc2_count); - c_printf("\n Registered timer array contents:\n"); - c_printf(" %-5s %-10s %-10s %-13s %-10s %-10s %-10s\n", "idx", "ptr", "expire", "period(tick)", "period(ms)", "fire(tick)", "fire(ms)"); - - for(uint32 i=0; i < timer_registry.used; i++){ - time_till_fire = (timer_array[i]->timer_expire - frc2_count); - c_printf(" %-5d %-10p %-10d %-13d %-10d %-10d %-10d\n", i, timer_array[i], timer_array[i]->timer_expire, timer_array[i]->timer_period, (uint32)(timer_array[i]->timer_period/312.5), time_till_fire, (uint32)(time_till_fire/312.5)); - - } - - return; -} - -void swtmr_print_suspended(void){ - os_timer_t** susp_timer_array = suspended_timers.data_ptr; - - c_printf("\n array used(%u)/size(%u)\ttotal size(bytes)=%u\n", - suspended_timers.used, suspended_timers.array_size, suspended_timers.array_size * suspended_timers.data_size); - c_printf("\n Suspended timer array contents:\n"); - c_printf(" %-5s %-10s %-15s %-15s %-14s %-10s\n", "idx", "ptr", "time left(tick)", "time left(ms)", "period(tick)", "period(ms)"); - - for(uint32 i=0; i < suspended_timers.used; i++){ - c_printf(" %-5d %-10p %-15d %-15d %-14d %-10d\n", i, susp_timer_array[i], susp_timer_array[i]->timer_expire, (uint32)(susp_timer_array[i]->timer_expire/312.5), susp_timer_array[i]->timer_period, (uint32)(susp_timer_array[i]->timer_period/312.5)); - - } - return; -} - -void swtmr_print_timer_list(void){ - volatile uint32 frc2_count=RTC_REG_READ(FRC2_COUNT_ADDRESS); - os_timer_t* timer_list_ptr=NULL; - uint32 time_till_fire=0; - c_printf("\n\tcurrent FRC2 count:%u\n", frc2_count); - c_printf(" timer_list contents:\n"); - c_printf(" %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", "ptr", "expire", "period", "func", "arg", "fire(tick)", "fire(ms)"); - - ETS_INTR_LOCK(); - - timer_list_ptr=timer_list; - - while(timer_list_ptr != NULL){ - time_till_fire=(timer_list_ptr->timer_expire - frc2_count) / 312.5; - - c_printf(" %-10p %-10u %-10u %-10p %-10p %-10u %-10u\n", - timer_list_ptr, (uint32)(timer_list_ptr->timer_expire), - (uint32)(timer_list_ptr->timer_period ), timer_list_ptr->timer_func, - timer_list_ptr->timer_arg, (timer_list_ptr->timer_expire - frc2_count), time_till_fire); - - timer_list_ptr=timer_list_ptr->timer_next; - } - ETS_INTR_UNLOCK(); - c_printf(" NOTE: some timers in the above list belong to the SDK and can not be suspended\n"); - return; -} - -#endif - -int swtmr_suspend(os_timer_t* timer_ptr){ - int return_value = SWTMR_OK; - - if(timer_ptr != NULL){ - // Timer pointer was provided, suspending specified timer - - return_value = timer_do_suspend(timer_ptr); - - if(return_value != SWTMR_OK){ - return return_value; - } - } - else{ - //timer pointer not found, suspending all timers - - if(timer_registry.data_ptr == NULL){ - return SWTMR_REGISTRY_NO_REGISTERED_TIMERS; - } - - timer_registry_remove_unarmed(); - - os_timer_t** tmr_reg_arr = timer_registry.data_ptr; - os_timer_t* temp_ptr = tmr_reg_arr[0]; - - while(temp_ptr != NULL){ - return_value = timer_do_suspend(temp_ptr); - - if(return_value != SWTMR_OK){ - return return_value; - } - - temp_ptr = tmr_reg_arr[0]; - } - } - return return_value; -} - -int swtmr_resume(os_timer_t* timer_ptr){ - - if(suspended_timers.data_ptr == NULL){ - return SWTMR_SUSPEND_NO_SUSPENDED_TIMERS; - } - - os_timer_t** suspended_tmr_array = suspended_timers.data_ptr; - os_timer_t** suspended_timer_ptr = NULL; - int retval=SWTMR_OK; - - if(timer_ptr != NULL){ - suspended_timer_ptr = timer_suspended_check(timer_ptr); - if(suspended_timer_ptr == NULL){ - //timer not suspended - return SWTMR_SUSPEND_TIMER_NOT_SUSPENDED; - } - - retval = timer_do_resume_single(suspended_timer_ptr); - if(retval != SWTMR_OK){ - return retval; - } - } - else{ - suspended_timer_ptr = &suspended_tmr_array[0]; - - while(suspended_timers.used > 0){ - retval = timer_do_resume_single(suspended_timer_ptr); - if(retval != SWTMR_OK){ - SWTMR_ERR("Unable to continue resuming timers, error(%u)", retval); - return retval; - } - suspended_timer_ptr = &suspended_tmr_array[0]; - } - } - return SWTMR_OK; -} - -void swtmr_register(void* timer_ptr){ - if(timer_ptr == NULL){ - SWTMR_DBG("error: timer_ptr is NULL"); - return; - } - - registry_queue_t* queue_temp = c_zalloc(sizeof(registry_queue_t)); - - if(queue_temp == NULL){ - SWTMR_ERR("MALLOC FAIL! req:%u, free:%u", sizeof(registry_queue_t), system_get_free_heap_size()); - return; - } - queue_temp->timer_ptr = timer_ptr; - - if(register_queue == NULL){ - register_queue = queue_temp; - - if(timer_reg_task_id == false) timer_reg_task_id = task_get_id(timer_register_task); - task_post_low(timer_reg_task_id, false); - SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr); - } - else{ - registry_queue_t* register_queue_tail = register_queue; - - while(register_queue_tail->next != NULL){ - register_queue_tail = register_queue_tail->next; - } - - register_queue_tail->next = queue_temp; - SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr); - } - - return; -} - -void swtmr_unregister(void* timer_ptr){ - if(timer_ptr == NULL){ - SWTMR_DBG("error: timer_ptr is NULL"); - return; - } - - registry_queue_t* queue_temp = c_zalloc(sizeof(registry_queue_t)); - - if(queue_temp == NULL){ - SWTMR_ERR("MALLOC FAIL! req:%u, free:%u", sizeof(registry_queue_t), system_get_free_heap_size()); - return; - } - queue_temp->timer_ptr=timer_ptr; - - if(unregister_queue == NULL){ - unregister_queue = queue_temp; - if(timer_unreg_task_id==false) timer_unreg_task_id=task_get_id(timer_unregister_task); - task_post_low(timer_unreg_task_id, false); - SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr); - } - else{ - registry_queue_t* unregister_queue_tail=unregister_queue; - while(unregister_queue_tail->next != NULL){ - unregister_queue_tail=unregister_queue_tail->next; - } - unregister_queue_tail->next = queue_temp; -// SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr); - } - - return; -} - -const char* swtmr_errorcode2str(int error_value){ -#ifdef USE_SWTMR_ERROR_STRINGS - if(SWTMR_ERROR_STRINGS[error_value] == NULL){ - SWTMR_ERR("error string %d not found", error_value); - return NULL; - } - else{ - return SWTMR_ERROR_STRINGS[error_value]; - } -#else - SWTMR_ERR("error(%u)", error_value); - return "ERROR! for more info, use debug build"; -#endif - -} - -bool swtmr_suspended_test(os_timer_t* timer_ptr){ - os_timer_t** test_var = timer_suspended_check(timer_ptr); - if(test_var == NULL){ - return false; - } - return true; -} - -#endif diff --git a/app/websocket/websocketclient.c b/app/websocket/websocketclient.c index 4628bf8a..5ff7ab9d 100644 --- a/app/websocket/websocketclient.c +++ b/app/websocket/websocketclient.c @@ -40,6 +40,8 @@ #include "../crypto/digests.h" #include "../crypto/mech.h" +#include "pm/swtimer.h" + #define PROTOCOL_SECURE "wss://" #define PROTOCOL_INSECURE "ws://" @@ -560,6 +562,7 @@ static void ws_initReceiveCallback(void *arg, char *buf, unsigned short len) { os_timer_disarm(&ws->timeoutTimer); os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_sendPingTimeout, conn); + SWTIMER_REG_CB(ws_sendPingTimeout, SWTIMER_RESUME) os_timer_arm(&ws->timeoutTimer, WS_PING_INTERVAL_MS, true); espconn_regist_recvcb(conn, ws_receiveCallback); @@ -706,6 +709,7 @@ static void dns_callback(const char *hostname, ip_addr_t *addr, void *arg) { // Set connection timeout timer os_timer_disarm(&ws->timeoutTimer); os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_connectTimeout, conn); + SWTIMER_REG_CB(ws_connectTimeout, SWTIMER_RESUME) os_timer_arm(&ws->timeoutTimer, WS_CONNECT_TIMEOUT_MS, false); if (ws->isSecure) { @@ -867,6 +871,7 @@ void ws_close(ws_info *ws) { os_timer_disarm(&ws->timeoutTimer); os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_forceCloseTimeout, ws->conn); + SWTIMER_REG_CB(ws_forceCloseTimeout, SWTIMER_RESUME); os_timer_arm(&ws->timeoutTimer, WS_FORCE_CLOSE_TIMEOUT_MS, false); } } diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index 2e1d092f..c2979a9c 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -333,30 +333,32 @@ Put NodeMCU in light sleep mode to reduce current consumption. * NodeMCU can not enter light sleep mode if wifi is suspended. * All active timers will be suspended and then resumed when NodeMCU wakes from sleep. -* Any previously suspended timers will be resumed when NodeMCU wakes from sleep. !!! attention This is disabled by default. Modify `PMSLEEP_ENABLE` in `app/include/user_config.h` to enable it. #### Syntax -`node.sleep({wake_gpio[, duration, int_type, resume_cb, preserve_mode]})` + +`node.sleep({wake_pin[, int_type, resume_cb, preserve_mode]})` #### Parameters -- `duration` Sleep duration in microseconds(μs). If a sleep duration of `0` is specified, suspension will be indefinite (Range: 0 or 50000 - 268435454 μs (0:4:28.000454)) -- `wake_pin` 1-12, pin to attach wake interrupt to. Note that pin 0(GPIO 16) does not support interrupts. - - If sleep duration is indefinite, `wake_pin` must be specified - - Please refer to the [`GPIO module`](gpio.md) for more info on the pin map. -- `int_type` type of interrupt that you would like to wake on. (Optional, Default: `node.INT_LOW`) - - valid interrupt modes: - - `node.INT_UP` Rising edge - - `node.INT_DOWN` Falling edge - - `node.INT_BOTH` Both edges - - `node.INT_LOW` Low level - - `node.INT_HIGH` High level -- `resume_cb` Callback to execute when WiFi wakes from suspension. (Optional) -- `preserve_mode` preserve current WiFi mode through node sleep. (Optional, Default: true) - - If true, Station and StationAP modes will automatically reconnect to previously configured Access Point when NodeMCU resumes. - - If false, discard WiFi mode and leave NodeMCU in `wifi.NULL_MODE`. WiFi mode will be restored to original mode on restart. + + + +* `wake_pin` 1-12, pin to attach wake interrupt to. Note that pin 0(GPIO 16) does not support interrupts. + + * Please refer to the [`GPIO module`](gpio.md) for more info on the pin map. +* `int_type` type of interrupt that you would like to wake on. (Optional, Default: `node.INT_LOW`) + * valid interrupt modes: + * `node.INT_UP` Rising edge + * `node.INT_DOWN` Falling edge + * `node.INT_BOTH` Both edges + * `node.INT_LOW` Low level + * `node.INT_HIGH` High level +* `resume_cb` Callback to execute when WiFi wakes from suspension. (Optional) +* `preserve_mode` preserve current WiFi mode through node sleep. (Optional, Default: true) + * If true, Station and StationAP modes will automatically reconnect to previously configured Access Point when NodeMCU resumes. + * If false, discard WiFi mode and leave NodeMCU in `wifi.NULL_MODE`. WiFi mode will be restored to original mode on restart. #### Returns - `nil` @@ -379,15 +381,15 @@ Put NodeMCU in light sleep mode to reduce current consumption. cfg.preserve_mode=false node.sleep(cfg) - +``` + #### See also - [`wifi.suspend()`](wifi.md#wifisuspend) diff --git a/docs/en/modules/tmr.md b/docs/en/modules/tmr.md index 74fbb072..919682d2 100644 --- a/docs/en/modules/tmr.md +++ b/docs/en/modules/tmr.md @@ -62,11 +62,9 @@ Functions supported in timer object: - [`t:alarm()`](#tmralarm) - [`t:interval()`](#tmrinterval) - [`t:register()`](#tmrregister) -- [`t:resume()`](#tmrresume) - [`t:start()`](#tmrstart) - [`t:state()`](#tmrstate) - [`t:stop()`](#tmrstop) -- [`t:suspend()`](#tmrsuspend) - [`t:unregister()`](#tmrunregister) #### Parameters @@ -184,61 +182,6 @@ mytimer:start() - [`tmr.create()`](#tmrcreate) - [`tmr.alarm()`](#tmralarm) -## tmr.resume() - -Resume an individual timer. - -Resumes a timer that has previously been suspended with either `tmr.suspend` or `tmr.suspend_all` - -#### Syntax -`tmr.resume(id/ref)` - -#### Parameters -`id/ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate)) - -#### Returns -`true` if timer was resumed successfully - -#### Example -```lua ---resume timer mytimer -mytimer:resume() - ---alternate metod -tmr.resume(mytimer) - -``` -#### See also -- [`tmr.suspend()`](#tmrsuspend) -- [`tmr.suspend_all()`](#tmrsuspendall) -- [`tmr.resume_all()`](#tmrresumeall) - -## tmr.resume_all() - -Resume all timers. - -Resumes all timers including those previously been suspended with either `tmr.suspend` or `tmr.suspend_all` - -#### Syntax -`tmr.resume_all()` - -#### Parameters -none - -#### Returns -`true` if timers were resumed successfully - -#### Example -```lua ---resume all previously suspended timers -tmr.resume_all() - -``` -#### See also -- [`tmr.suspend()`](#tmrsuspend) -- [`tmr.suspend_all()`](#tmrsuspendall) -- [`tmr.resume()`](#tmrresume) - ## tmr.softwd() Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted. @@ -336,72 +279,6 @@ if not mytimer:stop() then print("timer not stopped, not registered?") end - [`tmr.stop()`](#tmrstop) - [`tmr.unregister()`](#tmrunregister) -## tmr.suspend() - -Suspend an armed timer. - -!!! attention - This is disabled by default. Modify `ENABLE_TIMER_SUSPEND` in `app/include/user_config.h` to enable it. - -* Timers can be suspended at any time after they are armed. -* If a timer is rearmed with `tmr.start` or `tmr.alarm` any matching suspended timers will be discarded. - -#### Syntax -`tmr.suspend(id/ref)` - -#### Parameters -`id/ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate)) - -#### Returns -`true` if timer was resumed successfully - -#### Example -```lua ---suspend timer mytimer -mytimer:suspend() - ---alternate metod -tmr.suspend(mytimer) - -``` -#### See also -- [`tmr.suspend_all()`](#tmrsuspendall) -- [`tmr.resume()`](#tmrresume) -- [`tmr.resume_all()`](#tmrresumeall) - - -## tmr.suspend_all() - -Suspend all currently armed timers. - -!!! attention - This is disabled by default. Modify `ENABLE_TIMER_SUSPEND` in `app/include/user_config.h` to enable it. - -!!! Warning - This function suspends ALL active timers, including any active timers started by the NodeMCU subsystem or other modules. this may cause parts of your program to stop functioning properly. - USE THIS FUNCTION AT YOUR OWN RISK! - -#### Syntax -`tmr.suspend_all()` - -#### Parameters -none - -#### Returns -`true` if timers were suspended successfully - -#### Example -```lua ---suspend timer mytimer -tmr.suspend_all() - -``` -#### See also -- [`tmr.suspendl()`](#tmrsuspend) -- [`tmr.resume()`](#tmrresume) -- [`tmr.resume_all()`](#tmrresumeall) - - ## tmr.time() Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero. diff --git a/sdk-overrides/include/osapi.h b/sdk-overrides/include/osapi.h index 3f89877c..7b751c37 100644 --- a/sdk-overrides/include/osapi.h +++ b/sdk-overrides/include/osapi.h @@ -15,15 +15,4 @@ void call_user_start(void); #include_next "osapi.h" -#ifdef ENABLE_TIMER_SUSPEND -extern void swtmr_register(void* timer_ptr); -#undef os_timer_arm -#define os_timer_arm(timer_ptr, duration, mode) do{swtmr_register(timer_ptr); \ - ets_timer_arm_new(timer_ptr, duration, mode, 1);}while(0); - -extern void swtmr_unregister(void* timer_ptr); -#undef os_timer_disarm -#define os_timer_disarm(timer_ptr) do{swtmr_unregister(timer_ptr); ets_timer_disarm(timer_ptr);}while(0); -#endif - #endif From f427951f7909b430f78cd9832e59ede905e3e330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Wed, 18 Apr 2018 19:58:09 +0200 Subject: [PATCH 07/21] Editorial fix --- docs/en/modules/tcs34725.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/en/modules/tcs34725.md b/docs/en/modules/tcs34725.md index ae5a553c..bd1dd63d 100644 --- a/docs/en/modules/tcs34725.md +++ b/docs/en/modules/tcs34725.md @@ -5,11 +5,13 @@ This module provides a simple interface to [TCS34725 colour/light sensors](https://www.adafruit.com/product/1334) (Adafruit). -Note that you must call [`setup()`](#tcs34725setup) before you can start reading values! +!!! Warning + + You must call [`setup()`](#tcs34725setup) before you can start reading values! ## tcs34725.setup() -setupializes module. setupialization is mandatory before values can be read. +Initialization via this call is mandatory before values can be read. #### Syntax From 2e201cd8357425c8c801d82da198683330f3dc63 Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 22 Apr 2018 18:36:23 -0700 Subject: [PATCH 08/21] Fixed coding errors in app/pm/swtimer.c --- app/pm/swtimer.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/pm/swtimer.c b/app/pm/swtimer.c index bedbf954..43c1ae5a 100644 --- a/app/pm/swtimer.c +++ b/app/pm/swtimer.c @@ -1,3 +1,9 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Wall" +#pragma GCC diagnostic warning "-Wextra" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + /* swTimer.c SDK timer suspend API * * SDK software timer API info: @@ -57,7 +63,7 @@ //this section specifies which lua registry to use. LUA_GLOBALSINDEX or LUA_REGISTRYINDEX #ifdef SWTMR_DEBUG -#define SWTMR_DBG(fmt, ...) c_printf("\n SWTMR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__) +#define SWTMR_DBG(fmt, ...) dbg_printf("\n SWTMR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__) #define L_REGISTRY LUA_GLOBALSINDEX #define CB_LIST_STR "timer_cb_ptrs" #define SUSP_LIST_STR "suspended_tmr_LL_head" @@ -83,7 +89,7 @@ typedef struct cb_registry_item{ /* Internal variables */ static tmr_cb_queue_t* register_queue = NULL; -static task_handle_t cb_register_task_id = NULL; //variable to hold task id for task handler(process_cb_register_queue) +static task_handle_t cb_register_task_id = 0; //variable to hold task id for task handler(process_cb_register_queue) /* Function declarations */ //void swtmr_cb_register(void* timer_cb_ptr, uint8 resume_policy); @@ -173,7 +179,7 @@ void swtmr_suspend_timers(){ */ while(timer_ptr != NULL){ os_timer_t* next_timer = (os_timer_t*)0xffffffff; - for(int i = 0; i < registered_cb_qty; i++){ + for(size_t i = 0; i < registered_cb_qty; i++){ if(timer_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){ //current timer will be suspended, next timer's pointer will be needed to continue processing timer_list @@ -394,7 +400,7 @@ static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy){ tmr_cb_queue_t* queue_temp = c_zalloc(sizeof(tmr_cb_queue_t)); if(!queue_temp){ //it's boot time currently and we're already out of memory, something is very wrong... - c_printf("\n\t%s:out of memory, system halted!\n", __FUNCTION__); + dbg_printf("\n\t%s:out of memory, system halted!\n", __FUNCTION__); while(1) system_soft_wdt_feed(); } @@ -476,8 +482,8 @@ int print_timer_list(lua_State* L){ os_timer_t* timer_list_ptr = timer_list; - c_printf("\n\tCurrent FRC2: %u\n", RTC_REG_READ(FRC2_COUNT_ADDRESS)); - c_printf("\ttimer_list:\n"); + dbg_printf("\n\tCurrent FRC2: %u\n", RTC_REG_READ(FRC2_COUNT_ADDRESS)); + dbg_printf("\ttimer_list:\n"); while(timer_list_ptr != NULL){ bool registered_flag = FALSE; for(int i=0; i < registered_cb_qty; i++){ @@ -486,7 +492,7 @@ int print_timer_list(lua_State* L){ break; } } - c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\t%s\n", + dbg_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\t%s\n", timer_list_ptr, timer_list_ptr->timer_func, timer_list_ptr->timer_expire, timer_list_ptr->timer_period, timer_list_ptr->timer_next, registered_flag ? "Registered" : ""); timer_list_ptr = timer_list_ptr->timer_next; } @@ -513,9 +519,9 @@ int print_susp_timer_list(lua_State* L){ } os_timer_t* susp_timer_list_ptr = lua_touserdata(L, -1); - c_printf("\n\tsuspended_timer_list:\n"); + dbg_printf("\n\tsuspended_timer_list:\n"); while(susp_timer_list_ptr != NULL){ - c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\n",susp_timer_list_ptr, susp_timer_list_ptr->timer_func, susp_timer_list_ptr->timer_expire, susp_timer_list_ptr->timer_period, susp_timer_list_ptr->timer_next); + dbg_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\n",susp_timer_list_ptr, susp_timer_list_ptr->timer_func, susp_timer_list_ptr->timer_expire, susp_timer_list_ptr->timer_period, susp_timer_list_ptr->timer_next); susp_timer_list_ptr = susp_timer_list_ptr->timer_next; } return 0; From 2735426fc0cd838caea44411163a2cc02b3c9652 Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 22 Apr 2018 22:02:55 -0700 Subject: [PATCH 09/21] Removed pragma defines that were mistakenly left in --- app/pm/swtimer.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/pm/swtimer.c b/app/pm/swtimer.c index 43c1ae5a..802a2ee4 100644 --- a/app/pm/swtimer.c +++ b/app/pm/swtimer.c @@ -1,9 +1,3 @@ -#if defined(__GNUC__) -#pragma GCC diagnostic warning "-Wall" -#pragma GCC diagnostic warning "-Wextra" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - /* swTimer.c SDK timer suspend API * * SDK software timer API info: From da2bc7395d70a909b037a7a60073e019713b47dd Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 22 Apr 2018 22:18:36 -0700 Subject: [PATCH 10/21] Changed out of memory response from system halt to system restart --- app/pm/swtimer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/pm/swtimer.c b/app/pm/swtimer.c index 802a2ee4..9042b3b1 100644 --- a/app/pm/swtimer.c +++ b/app/pm/swtimer.c @@ -394,9 +394,8 @@ static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy){ tmr_cb_queue_t* queue_temp = c_zalloc(sizeof(tmr_cb_queue_t)); if(!queue_temp){ //it's boot time currently and we're already out of memory, something is very wrong... - dbg_printf("\n\t%s:out of memory, system halted!\n", __FUNCTION__); - while(1) - system_soft_wdt_feed(); + dbg_printf("\n\t%s:out of memory, rebooting.", __FUNCTION__); + system_restart(); } queue_temp->tmr_cb_ptr = timer_cb_ptr; queue_temp->suspend_policy = suspend_policy; From 5e1ca234cce36f251edd78dc3d5a5ce4d4c76a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Tue, 24 Apr 2018 13:58:10 +0200 Subject: [PATCH 11/21] Fix config reference --- docs/en/modules/sqlite3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/modules/sqlite3.md b/docs/en/modules/sqlite3.md index a18f382e..bba6647c 100644 --- a/docs/en/modules/sqlite3.md +++ b/docs/en/modules/sqlite3.md @@ -9,7 +9,7 @@ This module depens on [SQLite3](http://www.sqlite.org/) library developed by Dwa For instruction on how to use this module or further documentation, please, refer to [LuaSQLite3 Documentation](http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki). -This module is a stripped down version of SQLite, with every possible OMIT_\* configuration enable. The enabled OMIT_\* directives are available in the module's [Makefile](../../../app/sqlite3/Makefile). +This module is a stripped down version of SQLite, with every possible OMIT_\* configuration enable. The enabled OMIT_\* directives are available in the module's [config file](../../../app/sqlite3/config_ext.h). The SQLite3 module vfs layer integration with NodeMCU was developed by me. From 6069ebdc9090b0e16bcfacedde4c359bdef6d702 Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Thu, 26 Apr 2018 13:45:24 -0700 Subject: [PATCH 12/21] Update node.dsleep() to support longer deep sleep duration. (#2358) * Update node.dsleep() to support longer deep sleep duration. * Updated documentation for node.dsleepMax() --- app/modules/node.c | 12 +++++++++--- docs/en/modules/node.md | 42 ++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/modules/node.c b/app/modules/node.c index 10e7a639..efdf9491 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -38,10 +38,15 @@ static int node_restart( lua_State* L ) return 0; } +static int dsleepMax( lua_State *L ) { + lua_pushnumber(L, (uint64_t)system_rtc_clock_cali_proc()*(0x80000000-1)/(0x1000)); + return 1; +} + // Lua: dsleep( us, option ) static int node_deepsleep( lua_State* L ) { - uint32 us; + uint64 us; uint8 option; //us = luaL_checkinteger( L, 1 ); // Set deleep option, skip if nil @@ -592,8 +597,9 @@ static const LUA_REG_TYPE node_task_map[] = { static const LUA_REG_TYPE node_map[] = { - { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, - { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, + { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, + { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, + { LSTRKEY( "dsleepMax" ), LFUNCVAL( dsleepMax ) }, #ifdef PMSLEEP_ENABLE { LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) }, PMSLEEP_INT_MAP, diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index c2979a9c..39efc83c 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -87,9 +87,8 @@ dofile("hello.lc") Enters deep sleep mode, wakes up when timed out. -The maximum sleep time is 4294967295us, ~71 minutes. This is an SDK limitation. -Firmware from before 05 Jan 2016 have a maximum sleeptime of ~35 minutes. - +Theoretical maximum deep sleep duration can be found with [`node.dsleepMax()`](#nodedsleepmax) + !!! caution This function can only be used in the condition that esp8266 PIN32(RST) and PIN8(XPD_DCDC aka GPIO16) are connected together. Using sleep(0) will set no wake up timer, connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST. @@ -107,10 +106,7 @@ Firmware from before 05 Jan 2016 have a maximum sleeptime of ~35 minutes. - 1, RF_CAL after deep-sleep wake up, there will be large current - 2, no RF_CAL after deep-sleep wake up, there will only be small current - 4, disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current - - `instant` number (integer) or `nil`. If present and non-zero, do not use - the normal grace time before entering deep sleep. This is a largely - undocumented feature, and is only briefly mentioned in Espressif's - [low power solutions](https://espressif.com/sites/default/files/documentation/9b-esp8266_low_power_solutions_en.pdf#page=10) document (chapter 4.5). + - `instant` number (integer) or `nil`. If present and non-zero, the chip will enter Deep-sleep immediately and will not wait for the Wi-Fi core to be shutdown. #### Returns `nil` @@ -131,6 +127,38 @@ node.dsleep(nil,4) - [`wifi.suspend()`](wifi.md#wifisuspend) - [`wifi.resume()`](wifi.md#wifiresume) - [`node.sleep()`](#nodesleep) +- [`node.dsleepMax()`](#nodedsleepmax) + +## node.dsleepMax() + +Returns the current theoretical maximum deep sleep duration. + +!!! caution + + While it is possible to specify a longer sleep time than the theoretical maximum sleep duration, it is not recommended to exceed this maximum. + + +!!! note + + This theoretical maximum is dependent on ambient temperature. + (lower temp = shorter sleep duration, higher temp = longer sleep duration) + +#### Syntax +`node.dsleepMax()` + +#### Parameters + none + +#### Returns +`max_duration` + +#### Example +```lua +node.dsleep(node.dsleepMax()) +``` + +#### See also +- [`node.dsleep()`](#nodedsleep) ## node.flashid() From 53e44d5ecee74b14d5125037fac9e971cc55a362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Thu, 26 Apr 2018 22:56:43 +0200 Subject: [PATCH 13/21] Add reference to deep sleep post for details --- docs/en/modules/node.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index 39efc83c..d8176ff9 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -87,7 +87,7 @@ dofile("hello.lc") Enters deep sleep mode, wakes up when timed out. -Theoretical maximum deep sleep duration can be found with [`node.dsleepMax()`](#nodedsleepmax) +Theoretical maximum deep sleep duration can be found with [`node.dsleepMax()`](#nodedsleepmax). ["Max deep sleep for ESP8266"](https://thingpulse.com/max-deep-sleep-for-esp8266/) claims the realistic maximum be around 3.5h. !!! caution @@ -135,13 +135,12 @@ Returns the current theoretical maximum deep sleep duration. !!! caution - While it is possible to specify a longer sleep time than the theoretical maximum sleep duration, it is not recommended to exceed this maximum. + While it is possible to specify a longer sleep time than the theoretical maximum sleep duration, it is not recommended to exceed this maximum. In tests documented at ["Max deep sleep for ESP8266"](https://thingpulse.com/max-deep-sleep-for-esp8266/) the device never woke up again if the specified sleep time was beyond `dsleepMax()`. !!! note - This theoretical maximum is dependent on ambient temperature. - (lower temp = shorter sleep duration, higher temp = longer sleep duration) + This theoretical maximum is dependent on ambient temperature: lower temp = shorter sleep duration, higher temp = longer sleep duration #### Syntax `node.dsleepMax()` From 6a261aecdbdb172aa9b2b0c059d070a9f120a6c7 Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Mon, 7 May 2018 04:55:59 -0700 Subject: [PATCH 14/21] Fixed bug that caused crash when printing wifi.suspend disabled msg (#2365) --- app/modules/wifi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/modules/wifi.c b/app/modules/wifi.c index 8ff1db39..3eb68194 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -512,16 +512,16 @@ static int wifi_resume(lua_State* L) /* End WiFi suspend functions*/ #else -static char *susp_note_str = "\n The option \"pmsleep_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n"; +static char *susp_note_str = "\n The option \"PMSLEEP_ENABLE\" in \"app/include/user_config.h\" was disabled during FW build!\n"; static char *susp_unavailable_str = "wifi.suspend is unavailable"; static int wifi_suspend(lua_State* L){ - c_sprintf("%s", susp_note_str); + dbg_printf("%s", susp_note_str); return luaL_error(L, susp_unavailable_str); } static int wifi_resume(lua_State* L){ - c_sprintf("%s", susp_note_str); + dbg_printf("%s", susp_note_str); return luaL_error(L, susp_unavailable_str); } #endif From 106841c26c5a7cbfcb5977f287d386e4b7832b6a Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Tue, 8 May 2018 13:43:12 -0700 Subject: [PATCH 15/21] Add message indicating that node.sleep() was disabled during build. (#2367) --- app/modules/node.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/modules/node.c b/app/modules/node.c index efdf9491..a00bafd7 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -108,13 +108,18 @@ static int node_sleep( lua_State* L ) cfg.resume_cb_ptr = &node_sleep_resume_cb; pmSleep_suspend(&cfg); #else - c_printf("\n The option \"timer_suspend_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n"); - return luaL_error(L, "light sleep is unavailable"); + dbg_printf("\n The option \"TIMER_SUSPEND_ENABLE\" in \"app/include/user_config.h\" was disabled during FW build!\n"); + return luaL_error(L, "node.sleep() is unavailable"); #endif return 0; } +#else +static int node_sleep( lua_State* L ) +{ + dbg_printf("\n The options \"TIMER_SUSPEND_ENABLE\" and \"PMSLEEP_ENABLE\" in \"app/include/user_config.h\" were disabled during FW build!\n"); + return luaL_error(L, "node.sleep() is unavailable"); +} #endif //PMSLEEP_ENABLE - static int node_info( lua_State* L ) { lua_pushinteger(L, NODE_VERSION_MAJOR); @@ -600,8 +605,8 @@ static const LUA_REG_TYPE node_map[] = { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, { LSTRKEY( "dsleepMax" ), LFUNCVAL( dsleepMax ) }, -#ifdef PMSLEEP_ENABLE { LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) }, +#ifdef PMSLEEP_ENABLE PMSLEEP_INT_MAP, #endif { LSTRKEY( "info" ), LFUNCVAL( node_info ) }, From 914a4afc96136311db8ab923b8a6942f429d266f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnim=20L=C3=A4uger?= Date: Tue, 15 May 2018 20:55:31 +0200 Subject: [PATCH 16/21] Fix MQTT connect leak (#2368) * fix application of patch 0018-feat-espconn-Modification-for-espconn.patch in #2269 espconn_tcp_reconnect() was removed instead of espconn_list_delete() --- app/lwip/app/espconn_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lwip/app/espconn_tcp.c b/app/lwip/app/espconn_tcp.c index 49942e4e..b1ebfde4 100644 --- a/app/lwip/app/espconn_tcp.c +++ b/app/lwip/app/espconn_tcp.c @@ -434,9 +434,9 @@ espconn_Task(os_event_t *events) break; case SIG_ESPCONN_ERRER: /*remove the node from the client's active connection list*/ - espconn_list_delete(&plink_active, task_msg); if (espconn_manual_recv_enabled(task_msg)) espconn_list_delete(&plink_active, task_msg); + espconn_tcp_reconnect(task_msg); break; case SIG_ESPCONN_CLOSE: /*remove the node from the client's active connection list*/ From cbcb1b1a9ff9203869eb5458dc2d4b09f3f21ebb Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Fri, 18 May 2018 22:08:42 -0700 Subject: [PATCH 17/21] Fixed lack of nil return in file.read() when EOF is reached --- app/modules/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/modules/file.c b/app/modules/file.c index 670fab89..26a91d94 100644 --- a/app/modules/file.c +++ b/app/modules/file.c @@ -432,7 +432,8 @@ static int file_g_read( lua_State* L, int n, int16_t end_char, int fd ) luaM_free(L, heap_mem); heap_mem = NULL; } - return 0; + lua_pushnil(L); + return 1; } vfs_lseek(fd, -(n - i), VFS_SEEK_CUR); From dd02faef273a73f31fa172c266ab01b322e39f7e Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 20 May 2018 00:38:33 -0700 Subject: [PATCH 18/21] Add function node.getcpufreq() (#2375) --- app/modules/node.c | 8 ++++++++ docs/en/modules/node.md | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/modules/node.c b/app/modules/node.c index a00bafd7..3df88b8c 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -386,6 +386,13 @@ static int node_setcpufreq(lua_State* L) return 1; } +// Lua: freq = node.getcpufreq() +static int node_getcpufreq(lua_State* L) +{ + lua_pushinteger(L, system_get_cpu_freq()); + return 1; +} + // Lua: code, reason [, exccause, epc1, epc2, epc3, excvaddr, depc ] = bootreason() static int node_bootreason (lua_State *L) { @@ -622,6 +629,7 @@ static const LUA_REG_TYPE node_map[] = { LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) }, { LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) }, { LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) }, + { LSTRKEY( "getcpufreq" ), LFUNCVAL( node_getcpufreq) }, { LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) }, { LSTRKEY( "restore" ), LFUNCVAL( node_restore) }, { LSTRKEY( "random" ), LFUNCVAL( node_random) }, diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index d8176ff9..823e7650 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -185,6 +185,27 @@ none #### Returns flash size in bytes (integer) +## node.getcpufreq() + +Get the current CPU Frequency. + +#### Syntax +`node.getcpufreq()` + +#### Parameters +none + +#### Returns +Current CPU frequency (number) + +#### Example +```lua +do + local cpuFreq = node.getcpufreq() + print("The current CPU frequency is " .. cpuFreq .. " MHz") +end +``` + ## node.heap() Returns the current available heap size in bytes. Note that due to fragmentation, actual allocations of this size may not be possible. From 07ced6396969d13e17047e86bf30135ed4c8a3ff Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 20 May 2018 00:46:04 -0700 Subject: [PATCH 19/21] Dev wifi/wifi_eventmon malloc/free update (#2318) * updated wifi_eventmon to store events in LUA_REGISTRYINDEX * updated wifi_eventmon debug comments * Updated wifi.c to remove c_free() In wifi_ap_listclient(app/modules/wifi.c), c_free() was replaced with wifi_softap_free_station_info() * Removed unnecessary line of code from app/modules/wifi_eventmon.c --- app/modules/wifi.c | 7 +- app/modules/wifi_common.h | 22 +++--- app/modules/wifi_eventmon.c | 139 ++++++++++++++++++++---------------- 3 files changed, 88 insertions(+), 80 deletions(-) diff --git a/app/modules/wifi.c b/app/modules/wifi.c index 3eb68194..e0460c13 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -1787,7 +1787,7 @@ static int wifi_ap_listclient( lua_State* L ) { if (wifi_get_opmode() == STATION_MODE) { - return luaL_error( L, "Can't list client in STATION_MODE mode" ); + return luaL_error( L, "Can't list clients in STATION mode" ); } char temp[64]; @@ -1800,10 +1800,9 @@ static int wifi_ap_listclient( lua_State* L ) { c_sprintf(temp, MACSTR, MAC2STR(station->bssid)); wifi_add_sprintf_field(L, temp, IPSTR, IP2STR(&station->ip)); - next_station = STAILQ_NEXT(station, next); - c_free(station); - station = next_station; + station = STAILQ_NEXT(station, next); } + wifi_softap_free_station_info(); return 1; } diff --git a/app/modules/wifi_common.h b/app/modules/wifi_common.h index 122e4615..789633a3 100644 --- a/app/modules/wifi_common.h +++ b/app/modules/wifi_common.h @@ -19,21 +19,17 @@ void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...); void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer); -static inline void register_lua_cb(lua_State* L,int* cb_ref) -{ +static inline void register_lua_cb(lua_State* L,int* cb_ref){ int ref=luaL_ref(L, LUA_REGISTRYINDEX); - if( *cb_ref != LUA_NOREF) - { - luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); + if( *cb_ref != LUA_NOREF){ + luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); } *cb_ref = ref; } -static inline void unregister_lua_cb(lua_State* L, int* cb_ref) -{ - if(*cb_ref != LUA_NOREF) - { - luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); +static inline void unregister_lua_cb(lua_State* L, int* cb_ref){ + if(*cb_ref != LUA_NOREF){ + luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); *cb_ref = LUA_NOREF; } } @@ -47,13 +43,13 @@ void wifi_change_default_host_name(void); #endif #if defined(EVENT_DEBUG) || defined(NODE_DEBUG) -#define EVENT_DBG(...) c_printf(__VA_ARGS__) +#define EVENT_DBG(fmt, ...) c_printf("\n EVENT_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__) + #else #define EVENT_DBG(...) //c_printf(__VA_ARGS__) #endif -enum wifi_suspension_state -{ +enum wifi_suspension_state{ WIFI_AWAKE = 0, WIFI_SUSPENSION_PENDING = 1, WIFI_SUSPENDED = 2 diff --git a/app/modules/wifi_eventmon.c b/app/modules/wifi_eventmon.c index 66bd9827..06bce2a3 100644 --- a/app/modules/wifi_eventmon.c +++ b/app/modules/wifi_eventmon.c @@ -22,13 +22,6 @@ //variables for wifi event monitor static task_handle_t wifi_event_monitor_task_id; //variable to hold task id for task handler(process_event_queue) -typedef struct evt_queue{ - System_Event_t *evt; - struct evt_queue * next; -}evt_queue_t; //structure to hold pointers to event info and next item in queue - -static evt_queue_t *wifi_event_queue_head; //pointer to beginning of queue -static evt_queue_t *wifi_event_queue_tail; //pointer to end of queue static int wifi_event_cb_ref[EVENT_MAX+1] = { [0 ... EVENT_MAX] = LUA_NOREF}; //holds references to registered Lua callbacks #ifdef LUA_USE_MODULES_WIFI_MONITOR @@ -62,9 +55,11 @@ int wifi_event_monitor_register(lua_State* L) } } +static sint32_t event_queue_ref = LUA_NOREF; + static void wifi_event_monitor_handle_event_cb(System_Event_t *evt) { - EVENT_DBG("\n\twifi_event_monitor_handle_event_cb is called\n"); + EVENT_DBG("was called (Event:%d)", evt->event); #ifdef LUA_USE_MODULES_WIFI_MONITOR if (hook_fn && hook_fn(evt)) { @@ -79,38 +74,66 @@ static void wifi_event_monitor_handle_event_cb(System_Event_t *evt) evt->event == EVENT_SOFTAPMODE_STADISCONNECTED || evt->event == EVENT_SOFTAPMODE_PROBEREQRECVED || evt->event == EVENT_OPMODE_CHANGED))) { - evt_queue_t *temp = (evt_queue_t*)c_malloc(sizeof(evt_queue_t)); //allocate memory for new queue item - temp->evt = (System_Event_t*)c_malloc(sizeof(System_Event_t)); //allocate memory to hold event structure - if(!temp || !temp->evt) - { - luaL_error(lua_getstate(), "wifi.eventmon malloc: out of memory"); - return; + lua_State* L = lua_getstate(); + if(event_queue_ref == LUA_NOREF){ //if event queue has not been created, create it now + lua_newtable(L); + event_queue_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - c_memcpy(temp->evt, evt, sizeof(System_Event_t)); //copy event data to new struct + lua_rawgeti(L, LUA_REGISTRYINDEX, event_queue_ref); - if(wifi_event_queue_head == NULL && wifi_event_queue_tail == NULL)// if queue is empty add item to queue - { - wifi_event_queue_head = wifi_event_queue_tail = temp; - EVENT_DBG("\n\tqueue empty, adding event and posting task\n"); + System_Event_t* evt_tmp = lua_newuserdata(L, sizeof(System_Event_t)); + c_memcpy(evt_tmp, evt, sizeof(System_Event_t)); //copy event data to new struct + sint32_t evt_ud_ref = luaL_ref(L, LUA_REGISTRYINDEX); + size_t queue_len = lua_objlen(L, -1); + + //add event to queue + lua_pushnumber(L, queue_len+1); + lua_pushnumber(L, evt_ud_ref); + lua_rawset(L, -3); + + if(queue_len == 0){ //if queue was empty, post task + EVENT_DBG("Posting task"); task_post_low(wifi_event_monitor_task_id, false); } - else //if queue is not empty append item to end of queue - { - wifi_event_queue_tail->next=temp; - wifi_event_queue_tail=temp; - EVENT_DBG("\n\tqueue not empty, appending queue\n"); - } - } -} + else{ + EVENT_DBG("Appending queue, items in queue: %d", lua_objlen(L, -1)); + } + lua_pop(L, 1); + } //else{} //there are no callbacks registered, so the event can't be processed +} static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 priority) { lua_State* L = lua_getstate(); - evt_queue_t *temp = wifi_event_queue_head; //copy event_queue_head pointer to temporary pointer - System_Event_t *evt = temp->evt; //copy event data pointer to temporary pointer + lua_rawgeti(L, LUA_REGISTRYINDEX, event_queue_ref); + int index = 1; + lua_rawgeti(L, 1, index); + sint32 event_ref = lua_tonumber(L, -1); + lua_pop(L, 1); - EVENT_DBG("\t\tevent %u\n", evt->event); + //remove event reference from queue + int queue_length = lua_objlen(L, 1); + lua_rawgeti(L, 1, index); + for(; index0){ + task_post_low(wifi_event_monitor_task_id, false); //post task to process next item in queue + EVENT_DBG("%d events left in queue, posting task", queue_length); + } + lua_pop(L, 1); //pop event queue from stack if(wifi_event_cb_ref[evt->event] != LUA_NOREF) // check if user has registered a callback { @@ -130,107 +153,97 @@ static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 pri switch (evt->event) { case EVENT_STAMODE_CONNECTED: - EVENT_DBG("\n\tSTAMODE_CONNECTED\n"); + EVENT_DBG("Event: %d (STAMODE_CONNECTED)", EVENT_STAMODE_CONNECTED); wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.connected.ssid); wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.connected.bssid)); wifi_add_int_field(L, "channel", evt->event_info.connected.channel); - EVENT_DBG("\tConnected to SSID %s, Channel %d\n", + EVENT_DBG("Connected to SSID %s, Channel %d", evt->event_info.connected.ssid, evt->event_info.connected.channel); break; case EVENT_STAMODE_DISCONNECTED: - EVENT_DBG("\n\tSTAMODE_DISCONNECTED\n"); + EVENT_DBG("Event: %d (STAMODE_DISCONNECTED)", EVENT_STAMODE_DISCONNECTED); wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.disconnected.ssid); wifi_add_int_field(L, "reason", evt->event_info.disconnected.reason); wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.disconnected.bssid)); - EVENT_DBG("\tDisconnect from SSID %s, reason %d\n", + EVENT_DBG("Disconnect from SSID %s, reason %d", evt->event_info.disconnected.ssid, evt->event_info.disconnected.reason); break; case EVENT_STAMODE_AUTHMODE_CHANGE: - EVENT_DBG("\n\tSTAMODE_AUTHMODE_CHANGE\n"); + EVENT_DBG("Event: %d (STAMODE_AUTHMODE_CHANGE)", EVENT_STAMODE_AUTHMODE_CHANGE); wifi_add_int_field(L, "old_auth_mode", evt->event_info.auth_change.old_mode); wifi_add_int_field(L, "new_auth_mode", evt->event_info.auth_change.new_mode); - EVENT_DBG("\tAuthmode: %u -> %u\n", + EVENT_DBG("Authmode: %u -> %u", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); break; case EVENT_STAMODE_GOT_IP: - EVENT_DBG("\n\tGOT_IP\n"); + EVENT_DBG("Event: %d (STAMODE_GOT_IP)", EVENT_STAMODE_GOT_IP); wifi_add_sprintf_field(L, "IP", IPSTR, IP2STR(&evt->event_info.got_ip.ip)); wifi_add_sprintf_field(L, "netmask", IPSTR, IP2STR(&evt->event_info.got_ip.mask)); wifi_add_sprintf_field(L, "gateway", IPSTR, IP2STR(&evt->event_info.got_ip.gw)); - EVENT_DBG("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n", + EVENT_DBG("IP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "", IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw)); break; case EVENT_STAMODE_DHCP_TIMEOUT: - EVENT_DBG("\n\tSTAMODE_DHCP_TIMEOUT\n"); + EVENT_DBG("Event: %d (STAMODE_DHCP_TIMEOUT)", EVENT_STAMODE_DHCP_TIMEOUT); break; case EVENT_SOFTAPMODE_STACONNECTED: - EVENT_DBG("\n\tSOFTAPMODE_STACONNECTED\n"); + EVENT_DBG("Event: %d (SOFTAPMODE_STACONNECTED)", EVENT_SOFTAPMODE_STACONNECTED); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_connected.mac)); wifi_add_int_field(L, "AID", evt->event_info.sta_connected.aid); - EVENT_DBG("\tStation: " MACSTR "join, AID = %d\n", + EVENT_DBG("Station: " MACSTR "join, AID = %d", MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); break; case EVENT_SOFTAPMODE_STADISCONNECTED: - EVENT_DBG("\n\tSOFTAPMODE_STADISCONNECTED\n"); + EVENT_DBG("Event: %d (SOFTAPMODE_STADISCONNECTED)", EVENT_SOFTAPMODE_STADISCONNECTED); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_disconnected.mac)); wifi_add_int_field(L, "AID", evt->event_info.sta_disconnected.aid); - EVENT_DBG("\tstation: " MACSTR "leave, AID = %d\n", + EVENT_DBG("station: " MACSTR "leave, AID = %d", MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); break; case EVENT_SOFTAPMODE_PROBEREQRECVED: - EVENT_DBG("\n\tSOFTAPMODE_PROBEREQRECVED\n"); + EVENT_DBG("Event: %d (SOFTAPMODE_PROBEREQRECVED)", EVENT_SOFTAPMODE_PROBEREQRECVED); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.ap_probereqrecved.mac)); wifi_add_int_field(L, "RSSI", evt->event_info.ap_probereqrecved.rssi); - EVENT_DBG("Station PROBEREQ: " MACSTR " RSSI = %d\n", + EVENT_DBG("Station PROBEREQ: " MACSTR " RSSI = %d", MAC2STR(evt->event_info.ap_probereqrecved.mac), evt->event_info.ap_probereqrecved.rssi); break; case EVENT_OPMODE_CHANGED: - EVENT_DBG("\n\tOPMODE_CHANGED\n"); + EVENT_DBG("Event: %d (OPMODE_CHANGED)", EVENT_OPMODE_CHANGED); wifi_add_int_field(L, "old_mode", evt->event_info.opmode_changed.old_opmode); wifi_add_int_field(L, "new_mode", evt->event_info.opmode_changed.new_opmode); - EVENT_DBG("\topmode: %u -> %u\n", + EVENT_DBG("opmode: %u -> %u", evt->event_info.opmode_changed.old_opmode, evt->event_info.opmode_changed.new_opmode); break; default://if event is not implemented, return event id - EVENT_DBG("\n\tswitch/case default\n"); + EVENT_DBG("Event: %d (switch/case default)", evt->event); wifi_add_sprintf_field(L, "info", "event %u not implemented", evt->event); break; } + + luaL_unref(L, LUA_REGISTRYINDEX, event_ref); //the userdata containing event info is no longer needed + event_ref = LUA_NOREF; + lua_call(L, 1, 0); //execute user's callback and pass Lua table - - if (wifi_event_queue_head == wifi_event_queue_tail) //if queue is empty.. - { - wifi_event_queue_head = wifi_event_queue_tail = NULL; //set queue pointers to NULL - EVENT_DBG("\n\tQueue empty\n"); - } - else //if queue is not empty... - { - wifi_event_queue_head = wifi_event_queue_head->next; //append item to end of queue - EVENT_DBG("\n\tmore in queue, posting task...\n"); - task_post_low(wifi_event_monitor_task_id, false); //post task to process next item in queue - } - - c_free(evt); //free memory used by event structure - c_free(temp); //free memory used by queue structure + return; } #ifdef WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE From 7a54ae06c7cb570777e0cfa1c1b6df7981693703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnim=20L=C3=A4uger?= Date: Tue, 22 May 2018 14:55:14 +0200 Subject: [PATCH 20/21] Set safe defaults for scan config (#2378) --- app/modules/wifi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/modules/wifi.c b/app/modules/wifi.c index e0460c13..1e701547 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -1158,8 +1158,9 @@ static int wifi_station_listap( lua_State* L ) { return luaL_error( L, "Can't list ap in SOFTAP mode" ); } - struct scan_config scan_cfg; - memset(&scan_cfg, 0, sizeof(scan_cfg)); + // set safe defaults for scan time, all other members are initialized with 0 + // source: https://github.com/espressif/ESP8266_NONOS_SDK/issues/103 + struct scan_config scan_cfg = {.scan_time = {.passive=120, .active = {.max=120, .min=60}}}; getap_output_format=0; From 2cc195d5c9781677123d98f5dd3d43c36321503b Mon Sep 17 00:00:00 2001 From: Gergo Huszty Date: Mon, 4 Jun 2018 13:16:20 +0200 Subject: [PATCH 21/21] webap_toggle_pin.lua HTML warnings and typos fixed (#2394) --- lua_examples/webap_toggle_pin.lua | 56 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lua_examples/webap_toggle_pin.lua b/lua_examples/webap_toggle_pin.lua index 7d5a558d..60de70a6 100644 --- a/lua_examples/webap_toggle_pin.lua +++ b/lua_examples/webap_toggle_pin.lua @@ -1,31 +1,31 @@ wifi.setmode(wifi.SOFTAP) -wifi.ap.config({ssid="test",pwd="12345678"}) +wifi.ap.config({ ssid = "test", pwd = "12345678" }) gpio.mode(1, gpio.OUTPUT) -srv=net.createServer(net.TCP) -srv:listen(80,function(conn) - conn:on("receive", function(client,request) - local buf = "" - local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP") - if(method == nil)then - _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP") - end - local _GET = {} - if (vars ~= nil)then - for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do - _GET[k] = v - end - end - buf = buf.."

Hello, NodeMcu.

Turn PIN1
" - client:send(buf) - end) - conn:on("sent", function (c) c:close() end) +srv = net.createServer(net.TCP) +srv:listen(80, function(conn) + conn:on("receive", function(client, request) + local buf = "" + local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP") + if (method == nil) then + _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP") + end + local _GET = {} + if (vars ~= nil) then + for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do + _GET[k] = v + end + end + buf = buf .. "

Hello, this is NodeMCU.

Turn PIN1
" + client:send(buf) + end) + conn:on("sent", function(c) c:close() end) end)