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