From dda240cfec04a940885f871302ed426c4725543d Mon Sep 17 00:00:00 2001 From: dnc40085 Date: Sun, 10 Apr 2016 03:55:38 -0700 Subject: [PATCH] Exposed forced sleep API and more Added timer suspend functionality Added functions: * wifi.suspend * wifi.resume * node.sleep * tmr.suspend * tmr.suspend_all * tmr.resume * tmr.resume_all --- app/Makefile | 2 + app/include/swTimer/swTimer.h | 15 +- app/include/user_config.h | 4 + app/modules/Makefile | 1 + app/modules/node.c | 64 +++-- app/modules/tmr.c | 82 +++++- app/modules/wifi.c | 133 +++++---- app/modules/wifi_common.h | 9 + app/pm/Makefile | 52 ++++ app/pm/pmSleep.c | 374 +++++++++++++++++++++++++ app/pm/pmSleep.h | 56 ++++ app/swTimer/swTimer.c | 199 +++++++------ docs/en/modules/node.md | 70 +++++ docs/en/modules/tmr.md | 116 ++++++++ docs/en/modules/wifi.md | 88 +++++- sdk-overrides/include/ets_sys.h | 1 - sdk-overrides/include/osapi.h | 11 +- sdk-overrides/include/user_interface.h | 9 + 18 files changed, 1091 insertions(+), 195 deletions(-) create mode 100644 app/pm/Makefile create mode 100644 app/pm/pmSleep.c create mode 100644 app/pm/pmSleep.h diff --git a/app/Makefile b/app/Makefile index e752b40735..2a85a78d1b 100644 --- a/app/Makefile +++ b/app/Makefile @@ -49,6 +49,7 @@ SUBDIRS= \ websocket \ swTimer \ misc \ + pm \ endif # } PDIR @@ -95,6 +96,7 @@ COMPONENTS_eagle.app.v6 = \ dhtlib/libdhtlib.a \ tsl2561/tsl2561lib.a \ http/libhttp.a \ + pm/libpm.a \ websocket/libwebsocket.a \ esp-gdbstub/libgdbstub.a \ net/libnodemcu_net.a \ diff --git a/app/include/swTimer/swTimer.h b/app/include/swTimer/swTimer.h index 8c1a504106..50ee7db5f3 100644 --- a/app/include/swTimer/swTimer.h +++ b/app/include/swTimer/swTimer.h @@ -9,16 +9,15 @@ #define SWTMR_DEBUG #endif - #define SWTMR_DBG(fmt, ...) c_printf("\n SWTMR_DBG(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__) #else #define SWTMR_DBG(...) #endif -#if defined(SWTMR_ERROR) || defined(NODE_ERROR) +#if (defined(SWTMR_ERROR) || defined(NODE_ERROR)) #define SWTMR_ERR(fmt, ...) c_printf("\n SWTMR:"fmt"\n", ##__VA_ARGS__) #else - #define SWTMR_DBG(...) + #define SWTMR_ERR(...) #endif enum SWTMR_STATUS{ @@ -40,13 +39,11 @@ enum SWTMR_STATUS{ }; - - /* Global Function Declarations */ -void sw_timer_register(void* timer_ptr); -void sw_timer_unregister(void* timer_ptr); -int sw_timer_suspend(os_timer_t* timer_ptr); -int sw_timer_resume(os_timer_t* timer_ptr); +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); diff --git a/app/include/user_config.h b/app/include/user_config.h index c786e90955..03745f931d 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -116,6 +116,10 @@ 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 STRBUF_DEFAULT_INCREMENT 32 #endif /* __USER_CONFIG_H__ */ diff --git a/app/modules/Makefile b/app/modules/Makefile index 706b3a67f1..4da00b302d 100644 --- a/app/modules/Makefile +++ b/app/modules/Makefile @@ -55,6 +55,7 @@ INCLUDES += -I ../dhtlib INCLUDES += -I ../fatfs INCLUDES += -I ../http INCLUDES += -I ../websocket +INCLUDES += -I ../pm PDIR := ../$(PDIR) sinclude $(PDIR)Makefile diff --git a/app/modules/node.c b/app/modules/node.c index 12893943e4..4c208a4f93 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -66,19 +66,36 @@ static int node_deepsleep( lua_State* L ) return 0; } -// Lua: dsleep_set_options -// Combined to dsleep( us, option ) -// static int node_deepsleep_setoption( lua_State* L ) -// { -// s32 option; -// option = luaL_checkinteger( L, 1 ); -// if ( option < 0 || option > 4) -// return luaL_error( L, "wrong arg range" ); -// else -// deep_sleep_set_option( option ); -// return 0; -// } -// Lua: info() + +#ifdef PMSLEEP_ENABLE +#include "pmSleep.h" + +int node_sleep_resume_cb_ref= LUA_NOREF; +void node_sleep_resume_cb(void) +{ + PMSLEEP_DBG("START"); + pmSleep_execute_lua_cb(&node_sleep_resume_cb_ref); + PMSLEEP_DBG("END"); +} + +// Lua: node.sleep(table) +static int node_sleep( lua_State* L ) +{ + pmSleep_INIT_CFG(cfg); + cfg.sleep_mode=LIGHT_SLEEP_T; + + if(lua_istable(L, 1)){ + pmSleep_parse_table_lua(L, 1, &cfg, NULL, &node_sleep_resume_cb_ref); + } + else{ + return luaL_argerror(L, 1, "must be table"); + } + + cfg.resume_cb_ptr = &node_sleep_resume_cb; + pmSleep_suspend(&cfg); + return 0; +} +#endif //PMSLEEP_ENABLE static int node_info( lua_State* L ) { @@ -376,21 +393,6 @@ static int node_restore (lua_State *L) return 0; } -#include "swTimer/swTimer.h" - -static int node_suspend_timers (lua_State *L) -{ - lua_pushnumber(L, sw_timer_suspend(NULL)); - return 1; -} - -static int node_resume_timers (lua_State *L) -{ - lua_pushnumber(L, sw_timer_resume(NULL)); - return 1; -} - - #ifdef LUA_OPTIMIZE_DEBUG /* node.stripdebug([level[, function]]).  * level: 1 don't discard debug @@ -577,6 +579,10 @@ static const LUA_REG_TYPE node_map[] = { { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, +#ifdef PMSLEEP_ENABLE + { LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) }, + PMSLEEP_INT_MAP, +#endif { LSTRKEY( "info" ), LFUNCVAL( node_info ) }, { LSTRKEY( "chipid" ), LFUNCVAL( node_chipid ) }, { LSTRKEY( "flashid" ), LFUNCVAL( node_flashid ) }, @@ -592,8 +598,6 @@ static const LUA_REG_TYPE node_map[] = { LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) }, { LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) }, { LSTRKEY( "restore" ), LFUNCVAL( node_restore) }, - { LSTRKEY( "suspendTimers" ), LFUNCVAL( node_suspend_timers ) }, - { LSTRKEY( "resumeTimers" ), LFUNCVAL( node_resume_timers ) }, { LSTRKEY( "random" ), LFUNCVAL( node_random) }, #ifdef LUA_OPTIMIZE_DEBUG { LSTRKEY( "stripdebug" ), LFUNCVAL( node_stripdebug ) }, diff --git a/app/modules/tmr.c b/app/modules/tmr.c index be54bf74e8..76ee6d62e7 100755 --- a/app/modules/tmr.c +++ b/app/modules/tmr.c @@ -231,6 +231,8 @@ static int tmr_stop(lua_State* L){ return 1; } +#ifdef ENABLE_TIMER_SUSPEND + static int tmr_suspend(lua_State* L){ timer_t tmr = tmr_get(L, 1); @@ -238,13 +240,12 @@ static int tmr_suspend(lua_State* L){ return luaL_error(L, "timer not armed"); } - int retval = sw_timer_suspend(&tmr->os); + int retval = swtmr_suspend(&tmr->os); if(retval != SWTMR_OK){ return luaL_error(L, swtmr_errorcode2str(retval)); } else{ -// c_printf("tmr->mode & TIMER_SUSPEND_FLAG == %s",(tmr->mode & TIMER_SUSPEND_FLAG) ? "true" : "false"); lua_pushboolean(L, true); } @@ -258,19 +259,45 @@ static int tmr_resume(lua_State* L){ return luaL_error(L, "timer not suspended"); } - int retval = sw_timer_resume(&tmr->os); + int retval = swtmr_resume(&tmr->os); 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) +{ + 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; +} -// c_printf("tmr->mode & TIMER_SUSPEND_FLAG == %s",(tmr->mode & TIMER_SUSPEND_FLAG) ? "true" : "false"); +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; } + +#endif + // Lua: tmr.unregister( id / ref ) static int tmr_unregister(lua_State* L){ timer_t tmr = tmr_get(L, 1); @@ -316,7 +343,11 @@ 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; } @@ -396,6 +427,23 @@ static int tmr_create( lua_State *L ) { return 1; } + +#if defined(SWTMR_DEBUG) +static void tmr_printRegistry(lua_State* L){ + swtmr_print_registry(); +} + +static void tmr_printSuspended(lua_State* L){ + swtmr_print_suspended(); +} + +static void tmr_printTimerlist(lua_State* L){ + swtmr_print_timer_list(); +} + + +#endif + // Module function map static const LUA_REG_TYPE tmr_dyn_map[] = { @@ -406,13 +454,24 @@ static const LUA_REG_TYPE tmr_dyn_map[] = { { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) }, { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) }, { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) }, - { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, +#ifdef ENABLE_TIMER_SUSPEND + { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, +#endif { LSTRKEY( "__gc" ), LFUNCVAL( tmr_unregister ) }, { LSTRKEY( "__index" ), LROVAL( tmr_dyn_map ) }, { LNILKEY, LNILVAL } }; +#if 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 ) }, @@ -423,12 +482,19 @@ 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 { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, + { LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, + { LSTRKEY( "resume_all" ), LFUNCVAL( tmr_resume_all ) }, +#endif { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) }, { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) }, { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) }, { LSTRKEY( "create" ), LFUNCVAL( tmr_create ) }, +#if 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 ) }, @@ -444,12 +510,14 @@ 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; - os_timer_disarm(&alarm_timers[i].os); + //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); } last_rtc_time=system_get_rtc_time(); // Right now is time 0 last_rtc_time_us=0; - os_timer_disarm(&rtc_timer); + //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_setfn(&rtc_timer, rtc_callback, NULL); os_timer_arm(&rtc_timer, 1000, 1); return 0; diff --git a/app/modules/wifi.c b/app/modules/wifi.c index 1ac9306f02..de51c0555e 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -26,10 +26,6 @@ static uint8 getap_output_format=0; #define INVALID_MAC_STR "MAC:FF:FF:FF:FF:FF:FF" -//wifi.sleep variables -#define FPM_SLEEP_MAX_TIME 0xFFFFFFF -static bool FLAG_wifi_force_sleep_enabled=0; - #ifdef WIFI_SMART_ENABLE static void wifi_smart_succeed_cb(sc_status status, void *pdata){ NODE_DBG("wifi_smart_succeed_cb is called.\n"); @@ -283,67 +279,97 @@ static int wifi_getphymode( lua_State* L ) return 1; } -// Lua: wifi.sleep() -static int wifi_sleep(lua_State* L) +#ifdef PMSLEEP_ENABLE +/* Begin WiFi suspend functions*/ +#include "pmSleep.h" + +static int wifi_resume_cb_ref = LUA_NOREF; // Holds resume callback reference +static int wifi_suspend_cb_ref = LUA_NOREF; // Holds suspend callback reference + +void wifi_pmSleep_suspend_CB(void) { - uint8 desired_sleep_state = 2; - sint8 wifi_fpm_do_sleep_return_value = 1; - if(lua_isnumber(L, 1)) + PMSLEEP_DBG("\n\tDBG: %s start\n", __func__); + if (wifi_suspend_cb_ref != LUA_NOREF) { - if(luaL_checknumber(L, 1) == 0) - { - desired_sleep_state = 0; - } - else if(luaL_checknumber(L, 1) == 1) - { - desired_sleep_state = 1; - } + lua_State* L = lua_getstate(); // Get main Lua thread pointer + lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_suspend_cb_ref); // Push suspend callback onto stack + lua_unref(L, wifi_suspend_cb_ref); // remove suspend callback from LUA_REGISTRY + wifi_suspend_cb_ref = LUA_NOREF; // Update variable since reference is no longer valid + lua_call(L, 0, 0); // Execute suspend callback } - if (!FLAG_wifi_force_sleep_enabled && desired_sleep_state == 1 ) + else { - uint8 wifi_current_opmode = wifi_get_opmode(); - if (wifi_current_opmode == 1 || wifi_current_opmode == 3 ) - { - wifi_station_disconnect(); - } - // set WiFi mode to null mode - wifi_set_opmode(NULL_MODE); - // set force sleep type - wifi_fpm_set_sleep_type(MODEM_SLEEP_T); - wifi_fpm_open(); - wifi_fpm_do_sleep_return_value = wifi_fpm_do_sleep(FPM_SLEEP_MAX_TIME); - if (wifi_fpm_do_sleep_return_value == 0) - { - FLAG_wifi_force_sleep_enabled = TRUE; - } - else - { - wifi_fpm_close(); - FLAG_wifi_force_sleep_enabled = FALSE; - } - - } - else if(FLAG_wifi_force_sleep_enabled && desired_sleep_state == 0) + PMSLEEP_DBG("\n\tDBG: lua cb unavailable\n"); + } + PMSLEEP_DBG("\n\tDBG: %s end\n", __func__); + return; +} + +void wifi_pmSleep_resume_CB(void) +{ + PMSLEEP_DBG("\n\tDBG: %s start\n", __func__); + // If resume callback was defined + pmSleep_execute_lua_cb(&wifi_resume_cb_ref); + PMSLEEP_DBG("\n\tDBG: %s end\n", __func__); + return; +} + +// Lua: wifi.suspend({duration, suspend_cb, resume_cb, preserve_mode}) +static int wifi_suspend(lua_State* L) +{ + // If no parameters were provided + if (lua_isnone(L, 1)) { - FLAG_wifi_force_sleep_enabled = FALSE; - // wake up to use WiFi again - wifi_fpm_do_wakeup(); - wifi_fpm_close(); + // Return current WiFi suspension state + lua_pushnumber(L, pmSleep_get_state()); + return 1; // Return WiFi suspension state } - if (desired_sleep_state == 1 && FLAG_wifi_force_sleep_enabled == FALSE) + pmSleep_INIT_CFG(cfg); + cfg.sleep_mode=MODEM_SLEEP_T; + if(lua_istable(L, 1)) { - lua_pushnil(L); - lua_pushnumber(L, wifi_fpm_do_sleep_return_value); + pmSleep_parse_table_lua(L, 1, &cfg, &wifi_suspend_cb_ref, &wifi_resume_cb_ref); } else + return luaL_argerror(L, 1, "must be table"); + cfg.resume_cb_ptr = &wifi_pmSleep_resume_CB; + cfg.suspend_cb_ptr = &wifi_pmSleep_suspend_CB; + pmSleep_suspend(&cfg); + return 0; +} +// Lua: wifi.resume([Resume_CB]) +static int wifi_resume(lua_State* L) +{ + PMSLEEP_DBG("\n\tDBG: %s start\n", __func__); + uint8 fpm_state=pmSleep_get_state(); +// If forced sleep api is not enabled, return error + if (fpm_state==0) { - lua_pushnumber(L, FLAG_wifi_force_sleep_enabled); - lua_pushnil(L); + return luaL_error(L, "WIFi not suspended"); } - return 2; + + // If a resume callback was provided + if (lua_isfunction(L, 1)) + { + // If there is already a resume callback reference + lua_pushvalue(L, 1); //Push resume callback to the top of the stack + register_lua_cb(L, &wifi_resume_cb_ref); +// if (wifi_resume_cb_ref != LUA_NOREF) +// { +// luaL_unref(L, LUA_REGISTRYINDEX, wifi_resume_cb_ref); // Discard old callback +// } +// wifi_resume_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); // Register resume callback in LUA_REGISTRY and store it's reference + PMSLEEP_DBG("\n\tDBG: Resume CB registered\n"); + } + pmSleep_resume(NULL); + PMSLEEP_DBG("\n\tDBG: %s end\n", __func__); + return 0; } +/* End WiFi suspend functions*/ +#endif + // Lua: wifi.nullmodesleep() static int wifi_null_mode_auto_sleep(lua_State* L) { @@ -1490,7 +1516,10 @@ static const LUA_REG_TYPE wifi_map[] = { { LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) }, { LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) }, { LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) }, - { LSTRKEY( "sleep" ), LFUNCVAL( wifi_sleep ) }, +#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/wifi_common.h b/app/modules/wifi_common.h index 65b7a7bd0f..df8a77a74b 100644 --- a/app/modules/wifi_common.h +++ b/app/modules/wifi_common.h @@ -52,6 +52,15 @@ void wifi_change_default_host_name(void); #define EVENT_DBG(...) //c_printf(__VA_ARGS__) #endif +enum wifi_suspension_state +{ + WIFI_AWAKE = 0, + WIFI_SUSPENSION_PENDING = 1, + WIFI_SUSPENDED = 2 +}; + + + #ifdef WIFI_SDK_EVENT_MONITOR_ENABLE extern const LUA_REG_TYPE wifi_event_monitor_map[]; void wifi_eventmon_init(); diff --git a/app/pm/Makefile b/app/pm/Makefile new file mode 100644 index 0000000000..8143bb2afa --- /dev/null +++ b/app/pm/Makefile @@ -0,0 +1,52 @@ + +############################################################# +# 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 = libpm.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/pm/pmSleep.c b/app/pm/pmSleep.c new file mode 100644 index 0000000000..0b084e139f --- /dev/null +++ b/app/pm/pmSleep.c @@ -0,0 +1,374 @@ +#include "pmSleep.h" +#ifdef PMSLEEP_ENABLE +#define STRINGIFY_VAL(x) #x +#define STRINGIFY(x) STRINGIFY_VAL(x) + +//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"; + + +/* INTERNAL VARIABLES */ +static void (*user_suspend_cb)(void) = NULL; +static void (*user_resume_cb)(void) = NULL; +static uint8 resume_opmode = 0; +static os_timer_t wifi_suspended_test_timer; +static uint8 autosleep_setting_temp = 0; +static os_timer_t null_mode_check_timer; +static pmSleep_param_t current_config; + + +/* INTERNAL FUNCTION DECLARATIONS */ +static void disarm_all_timers(void); +static void null_mode_check_timer_cb(void* arg); +static void rearm_all_sw_timers(void); +static inline void register_lua_cb(lua_State* L,int* cb_ref); +static void resume_cb(void); +static void wifi_suspended_timer_cb(int arg); + +/* INTERNAL FUNCTIONS */ + +#include "swTimer/swTimer.h" +static void disarm_all_timers(void){ +#ifdef ENABLE_TIMER_SUSPEND + swtmr_suspend(NULL); +#endif + return; +} + +static void rearm_all_sw_timers(void){ +#ifdef ENABLE_TIMER_SUSPEND + swtmr_resume(NULL); +#endif + return; +} + +static void null_mode_check_timer_cb(void* arg){ + if (wifi_get_opmode() == NULL_MODE){ + os_timer_disarm(&null_mode_check_timer); + disarm_all_timers(); + + if(current_config.sleep_mode == LIGHT_SLEEP_T){ + PMSLEEP_DBG("wifi_fpm_do_sleep(%d)", current_config.sleep_duration); + wifi_fpm_do_sleep(current_config.sleep_duration); + return; + } + else{ + PMSLEEP_DBG("wifi_fpm_do_sleep(%d)", current_config.sleep_duration); + sint8 retval_wifi_fpm_do_sleep = wifi_fpm_do_sleep(current_config.sleep_duration); // Request WiFi suspension and store return value + + // If wifi_fpm_do_sleep success + if (retval_wifi_fpm_do_sleep == 0){ + PMSLEEP_DBG("wifi_fpm_do_sleep success, starting wifi_suspend_test timer"); + os_timer_disarm(&wifi_suspended_test_timer); + os_timer_setfn(&wifi_suspended_test_timer, (os_timer_func_t*)wifi_suspended_timer_cb, NULL); + os_timer_arm(&wifi_suspended_test_timer, 1, 1); + } + else{ // This should never happen. if it does, return the value for error reporting + + wifi_fpm_close(); + luaL_error(lua_getstate(), "wifi_fpm_do_sleep returned %d", retval_wifi_fpm_do_sleep); + return; + } + } + + } + else{ + PMSLEEP_DBG("wifi_get_opmode()!=NULL_MODE"); + } +} + + +//function to register a lua callback function in the LUA_REGISTRYINDEX for later execution +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); + *cb_ref = ref; +} + +// C callback for bringing WiFi back from forced sleep +static void resume_cb(void){ + PMSLEEP_DBG("START"); + //TODO: Add support for extended light sleep duration + wifi_fpm_close(); // Disable force sleep API + PMSLEEP_DBG("WiFi resume"); + + rearm_all_sw_timers(); + + //this section restores null mode auto sleep setting + if(autosleep_setting_temp == 1) { + wifi_fpm_auto_sleep_set_in_null_mode(autosleep_setting_temp); + autosleep_setting_temp = 0; + } + + //this section restores previous wifi mode + if (resume_opmode == STATION_MODE || resume_opmode == SOFTAP_MODE || resume_opmode == STATIONAP_MODE){ + if (wifi_set_opmode_current(resume_opmode)){ + if (resume_opmode == STATION_MODE || resume_opmode == STATIONAP_MODE){ + wifi_station_connect(); // Connect to currently configured Access Point + } + PMSLEEP_DBG("WiFi mode restored"); + resume_opmode = 0; // reset variable to default value + } + } + else{ + wifi_set_opmode_current(NULL_MODE); + } + + //execute the external resume callback + if (user_resume_cb != NULL){ + PMSLEEP_DBG("calling user resume cb (%p)", user_resume_cb); + user_resume_cb(); + user_resume_cb = NULL; + } + + PMSLEEP_DBG("END"); + return; +} + +// This callback executes the suspended callback when Wifi suspension is in effect +static void wifi_suspended_timer_cb(int arg){ + // check if wifi is suspended. + if (pmSleep_get_state() == PMSLEEP_SUSPENDED){ + os_timer_disarm(&wifi_suspended_test_timer); // Stop rf_closed_timer + PMSLEEP_DBG("WiFi is suspended"); + + //execute the external suspended callback + if (user_suspend_cb != NULL){ + PMSLEEP_DBG("calling user suspend cb (%p)", user_suspend_cb); + user_suspend_cb(); + user_suspend_cb = NULL; + } + PMSLEEP_DBG("END"); + } +} + +/* EXTERNAL FUNCTIONS */ + +//this function executes the application developer's Lua callback +void pmSleep_execute_lua_cb(int* cb_ref){ + if (*cb_ref != LUA_NOREF){ + lua_State* L = lua_getstate(); // Get Lua main thread pointer + lua_rawgeti(L, LUA_REGISTRYINDEX, *cb_ref); // Push resume callback onto the stack + lua_unref(L, *cb_ref); // Remove resume callback from registry + *cb_ref = LUA_NOREF; // Update variable since reference is no longer valid + lua_call(L, 0, 0); // Execute resume callback + } + +} + +//this function checks current wifi suspension state and returns the result +uint8 pmSleep_get_state(void){ + if (fpm_rf_is_closed()) return PMSLEEP_SUSPENDED; + else if (fpm_is_open()) return PMSLEEP_SUSPENSION_PENDING; + else return PMSLEEP_AWAKE; +} + +//this function parses the lua configuration table provided by the application developer +int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, int *suspend_lua_cb_ref, int *resume_lua_cb_ref){ + lua_Integer Linteger_tmp = 0; + + 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, PMSLEEP_DURATION_ERR_STR ); + } + 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) ){ + lua_pushvalue(L, -1); // Push resume callback to the top of the stack + register_lua_cb(L, suspend_lua_cb_ref); + } + else{ + return luaL_argerror( L, table_idx, "suspend_cb: must be function" ); + } + } + lua_pop(L, 1); + } + else if (cfg->sleep_mode == LIGHT_SLEEP_T){ //CPU suspend +#ifdef ENABLE_TIMER_SUSPEND + lua_getfield(L, table_idx, "wake_pin"); + if( !lua_isnil(L, -1) ){ /* found? */ + if( lua_isnumber(L, -1) ){ + Linteger_tmp=lua_tointeger(L, -1); + luaL_argcheck(L, (platform_gpio_exists(Linteger_tmp) && Linteger_tmp > 0), table_idx, "wake_pin: Invalid interrupt pin"); + cfg->wake_pin = Linteger_tmp; + } + else{ + 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" ); + } + lua_pop(L, 1); + + lua_getfield(L, table_idx, "int_type"); + if( !lua_isnil(L, -1) ){ /* found? */ + if( lua_isnumber(L, -1) ){ + Linteger_tmp=lua_tointeger(L, -1); + luaL_argcheck(L, (Linteger_tmp == GPIO_PIN_INTR_ANYEDGE || Linteger_tmp == GPIO_PIN_INTR_HILEVEL + || Linteger_tmp == GPIO_PIN_INTR_LOLEVEL || Linteger_tmp == GPIO_PIN_INTR_NEGEDGE + || Linteger_tmp == GPIO_PIN_INTR_POSEDGE ), 1, "int_type: invalid interrupt type"); + cfg->int_type = Linteger_tmp; + } + else{ + return luaL_argerror( L, table_idx, "int_type: must be number" ); + } + } + else{ + cfg->int_type = GPIO_PIN_INTR_LOLEVEL; + } + lua_pop(L, 1); +#endif + } + else{ + return luaL_error(L, "FPM Sleep mode not available"); + } + + lua_getfield(L, table_idx, "resume_cb"); + if( !lua_isnil(L, -1) ){ /* found? */ + if( lua_isfunction(L, -1) ){ + lua_pushvalue(L, -1); // Push resume callback to the top of the stack + register_lua_cb(L, resume_lua_cb_ref); + } + else{ + return luaL_argerror( L, table_idx, "resume_cb: must be function" ); + } + } + lua_pop(L, 1); + + lua_getfield(L, table_idx, "preserve_mode"); + if( !lua_isnil(L, -1) ){ /* found? */ + if( lua_isboolean(L, -1) ){ + cfg->preserve_opmode=lua_toboolean(L, -1); + } + else{ + return luaL_argerror( L, table_idx, "preseve_mode: must be boolean" ); + } + } + else{ + cfg->preserve_opmode = true; + } + lua_pop(L, 1); + + //if sleep duration is zero, set indefinite sleep duration + if( cfg->sleep_duration == 0 ){ + cfg->sleep_duration = FPM_SLEEP_MAX_TIME; + } + + return 0; +} + +//This function resumes ESP from MODEM_SLEEP +void pmSleep_resume(void (*resume_cb_ptr)(void)){ + PMSLEEP_DBG("START"); + uint8 fpm_state = pmSleep_get_state(); + + if(fpm_state>0){ + if(resume_cb_ptr != NULL){ + user_resume_cb = resume_cb_ptr; + } + wifi_fpm_do_wakeup(); // Wake up from sleep + resume_cb(); // Finish WiFi wakeup + } + + PMSLEEP_DBG("END"); + return; +} + +//this function puts the ESP8266 into MODEM_SLEEP or LIGHT_SLEEP +void pmSleep_suspend(pmSleep_param_t *cfg){ + PMSLEEP_DBG("START"); + + lua_State* L = lua_getstate(); +#ifndef ENABLE_TIMER_SUSPEND + if(cfg->sleep_mode == LIGHT_SLEEP_T){ + luaL_error(L, "timer suspend API is disabled, light sleep unavailable"); + return; + } +#endif + uint8 current_wifi_mode = wifi_get_opmode(); // Get Current WiFi mode + + user_resume_cb = cfg->resume_cb_ptr; //pointer to hold address of user_cb + user_suspend_cb = cfg->suspend_cb_ptr; //pointer to hold address of user_cb + + // If Preserve_wifi_mode parameter is TRUE and current WiFi mode is not NULL_MODE + if (cfg->preserve_opmode && current_wifi_mode != 0){ + resume_opmode = current_wifi_mode; + } + + + if (current_wifi_mode == STATION_MODE || current_wifi_mode == STATIONAP_MODE){ + wifi_station_disconnect(); // Disconnect from Access Point + } + + //the null mode sleep functionality interferes with the forced sleep API and must be disabled + if(get_fpm_auto_sleep_flag() == 1){ + autosleep_setting_temp = 1; + wifi_fpm_auto_sleep_set_in_null_mode(0); + } + + // If wifi_set_opmode_current is successful + if (wifi_set_opmode_current(NULL_MODE)){ + PMSLEEP_DBG("sleep_mode is %s", cfg->sleep_mode == MODEM_SLEEP_T ? "MODEM_SLEEP_T" : "LIGHT_SLEEP_T"); + + wifi_fpm_set_sleep_type(cfg->sleep_mode); + + wifi_fpm_open(); // Enable force sleep API + + if (cfg->sleep_mode == LIGHT_SLEEP_T){ +#ifdef ENABLE_TIMER_SUSPEND + 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); + + if((cfg->int_type != GPIO_PIN_INTR_ANYEDGE && cfg->int_type != GPIO_PIN_INTR_HILEVEL + && cfg->int_type != GPIO_PIN_INTR_LOLEVEL && cfg->int_type != GPIO_PIN_INTR_NEGEDGE + && cfg->int_type != GPIO_PIN_INTR_POSEDGE )){ + wifi_fpm_close(); + PMSLEEP_DBG("Invalid interrupt type"); + return; + } + + GPIO_DIS_OUTPUT(pin_num[cfg->wake_pin]); + PIN_FUNC_SELECT(pin_mux[cfg->wake_pin], pin_func[cfg->wake_pin]); + wifi_enable_gpio_wakeup(pin_num[cfg->wake_pin], cfg->int_type); + } + else if(cfg->sleep_duration == FPM_SLEEP_MAX_TIME && cfg->wake_pin == 255){ + wifi_fpm_close(); + PMSLEEP_DBG("No wake-up pin defined"); + return; + } +#endif + + } + + wifi_fpm_set_wakeup_cb(resume_cb); // Set resume C callback + + c_memcpy(¤t_config, cfg, sizeof(pmSleep_param_t)); + + os_timer_disarm(&null_mode_check_timer); + os_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false); + os_timer_arm(&null_mode_check_timer, 1, 1); + } + else{ + luaL_error(L, "ERR, mode change fail"); + } + PMSLEEP_DBG("END"); + return; +} + +#endif diff --git a/app/pm/pmSleep.h b/app/pm/pmSleep.h new file mode 100644 index 0000000000..7a8b59533e --- /dev/null +++ b/app/pm/pmSleep.h @@ -0,0 +1,56 @@ +#ifndef __FPM_SLEEP_H__ +#define __FPM_SLEEP_H__ +#include "user_interface.h" +#include "c_types.h" +#include "lauxlib.h" +#include "gpio.h" +#include "platform.h" +#include "task/task.h" +#include "c_string.h" + +//#define PMSLEEP_DEBUG + +#define PMSLEEP_SLEEP_MIN_TIME 50000 +#define PMSLEEP_SLEEP_MAX_TIME 268435454 //FPM_MAX_SLEEP_TIME-1 +#define pmSleep_INIT_CFG(X) pmSleep_param_t X = {.sleep_duration=0, .wake_pin=255, \ + .preserve_opmode=TRUE, .suspend_cb_ptr=NULL, .resume_cb_ptr=NULL} + +#define PMSLEEP_INT_MAP \ + { LSTRKEY( "INT_BOTH" ), LNUMVAL( GPIO_PIN_INTR_ANYEDGE ) }, \ + { LSTRKEY( "INT_UP" ), LNUMVAL( GPIO_PIN_INTR_POSEDGE ) }, \ + { LSTRKEY( "INT_DOWN" ), LNUMVAL( GPIO_PIN_INTR_NEGEDGE ) }, \ + { LSTRKEY( "INT_HIGH" ), LNUMVAL( GPIO_PIN_INTR_HILEVEL ) }, \ + { LSTRKEY( "INT_LOW" ), LNUMVAL( GPIO_PIN_INTR_LOLEVEL ) } + + +#if defined(PMSLEEP_DEBUG) || defined(NODE_DEBUG) + #define PMSLEEP_DBG(fmt, ...) c_printf("\tPMSLEEP_DBG(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__) +#else + #define PMSLEEP_DBG(...) //c_printf(__VA_ARGS__) +#endif + +typedef struct pmSleep_param{ + uint32 sleep_duration; + uint8 sleep_mode; + uint8 wake_pin; + uint8 int_type; + bool preserve_opmode; + void (*suspend_cb_ptr)(void); + void (*resume_cb_ptr)(void); +}pmSleep_param_t; //structure to hold pmSleep configuration + + +enum PMSLEEP_STATE{ + PMSLEEP_AWAKE = 0, + PMSLEEP_SUSPENSION_PENDING = 1, + PMSLEEP_SUSPENDED = 2 +}; + +uint8 pmSleep_get_state(void); +void pmSleep_resume(void (*resume_cb_ptr)(void)); +void pmSleep_suspend(pmSleep_param_t *param); +void pmSleep_execute_lua_cb(int* cb_ref); +int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, int *suspend_lua_cb_ref, int *resume_lua_cb_ref); + + +#endif // __FPM_SLEEP_H__ diff --git a/app/swTimer/swTimer.c b/app/swTimer/swTimer.c index 5c6380f43c..9014b3f2ac 100644 --- a/app/swTimer/swTimer.c +++ b/app/swTimer/swTimer.c @@ -2,12 +2,13 @@ * * SDK software timer API info: * - * The SDK software timer API executes in a task. The priority of this task in relation to the - * application level tasks is unknown. - * * 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. @@ -18,6 +19,7 @@ * 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: @@ -43,30 +45,28 @@ * * */ - - #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_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] = "Timer already suspended", - [SWTMR_SUSPEND_TIMER_ALREADY_REARMED] = "Timer has already been re-armed", - [SWTMR_SUSPEND_NO_SUSPENDED_TIMERS] = "No suspended timers available", - [SWTMR_SUSPEND_TIMER_NOT_SUSPENDED] = "Timer is not suspended", + [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 @@ -100,22 +100,26 @@ static void timer_unregister_task(task_param_t param, uint8 priority); //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; + 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; + 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; + 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; } @@ -124,24 +128,24 @@ static inline int timer_do_suspend(os_timer_t* timer_ptr){ SWTMR_DBG("timer_ptr is NULL"); return SWTMR_NULL_PTR; } + volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS); if(timer_armed_check(timer_ptr) == FALSE){ return SWTMR_TIMER_NOT_ARMED; } - if(timer_suspended_check(timer_ptr) != NULL){ - return SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED; - } + 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 = 6250; // 20 ms in ticks (1ms = 312.5 ticks) - else + 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); @@ -155,8 +159,11 @@ static inline int timer_do_suspend(os_timer_t* timer_ptr){ } } - if(!dynarr_add(&suspended_timers, &timer_ptr, sizeof(timer_ptr))){ - return SWTMR_SUSPEND_ARRAY_ADD_FAILED; + if(suspended_timer_ptr == NULL){ +// return SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED; + if(!dynarr_add(&suspended_timers, &timer_ptr, sizeof(timer_ptr))){ + return SWTMR_SUSPEND_ARRAY_ADD_FAILED; + } } return SWTMR_OK; @@ -171,13 +178,13 @@ static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ 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); + 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); dynarr_remove(&suspended_timers, suspended_timer_ptr); - return SWTMR_SUSPEND_TIMER_ALREADY_REARMED; + return SWTMR_OK; } //Prepare timer for resume @@ -186,24 +193,19 @@ static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ timer_register_task((task_param_t)resume_timer_ptr, false); SWTMR_DBG("Removing timer(%p) from suspend array", resume_timer_ptr); - if(!dynarr_remove(&suspended_timers, suspended_timer_ptr)){ - return SWTMR_SUSPEND_ARRAY_REMOVE_FAILED; - } - //This section performs the actual resume of the suspended timer - //block interrupts since the SDK software timer linked list will be modified + // 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; + resume_timer_ptr->timer_next = timer_list_ptr->timer_next; + timer_list_ptr->timer_next = resume_timer_ptr; break; } else{ @@ -211,8 +213,8 @@ static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ } } else{ - timer_list_ptr->timer_next=resume_timer_ptr; - resume_timer_ptr->timer_next=NULL; + timer_list_ptr->timer_next = resume_timer_ptr; + resume_timer_ptr->timer_next = NULL; break; } } @@ -220,7 +222,7 @@ static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ 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; } @@ -234,31 +236,43 @@ static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){ 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*))){ - //timer registry init Fail! + SWTMR_ERR("timer registry init Fail!"); return; } } - os_timer_t* timer_ptr=NULL; - if(param != false){ - timer_ptr=(os_timer_t*)param; + 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{ - if(register_queue==NULL){ + //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; + registry_queue_t* queue_temp = register_queue; + register_queue = register_queue->next; - c_free(queue_temp); + timer_ptr = queue_temp->timer_ptr; - if(register_queue != NULL){ -// SWTMR_DBG("register_queue not empty, posting task"); - task_post_low(timer_reg_task_id, false); - } + 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){ @@ -266,8 +280,6 @@ static void timer_register_task(task_param_t param, uint8 priority){ return; } -// SWTMR_DBG("adding timer(%p) to registry", timer_ptr); - if(!dynarr_add(&timer_registry, &timer_ptr, sizeof(timer_ptr))){ /**/SWTMR_ERR("Registry append failed"); return; @@ -277,14 +289,14 @@ static void timer_register_task(task_param_t param, uint8 priority){ } static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr){ - if(timer_registry.data_ptr==NULL){ + if(timer_registry.data_ptr == NULL){ return NULL; } if(timer_registry.used > 0){ os_timer_t** timer_registry_array = timer_registry.data_ptr; - for(int i=0; i < timer_registry.used; i++){ + 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]; @@ -296,12 +308,12 @@ static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr){ } static inline void timer_registry_remove_unarmed(void){ - if(timer_registry.data_ptr==NULL){ + if(timer_registry.data_ptr == NULL){ return; } if(timer_registry.used > 0){ os_timer_t** timer_registry_array = timer_registry.data_ptr; - for(int i=0; i < timer_registry.used; i++){ + 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); } @@ -309,15 +321,16 @@ static inline void timer_registry_remove_unarmed(void){ } } + static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr){ - if(suspended_timers.data_ptr==NULL){ + if(suspended_timers.data_ptr == NULL){ return NULL; } if(suspended_timers.used > 0){ os_timer_t** suspended_timer_array = suspended_timers.data_ptr; - for(int i=0; i < suspended_timers.used; i++){ + for(uint32 i=0; i < suspended_timers.used; i++){ if(suspended_timer_array[i] == timer_ptr){ return &suspended_timer_array[i]; } @@ -328,13 +341,13 @@ static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr){ } static void timer_unregister_task(task_param_t param, uint8 priority){ - if(timer_registry.data_ptr==NULL){ + if(timer_registry.data_ptr == NULL){ return; } - os_timer_t* timer_ptr=NULL; + os_timer_t* timer_ptr = NULL; if(param != false){ - timer_ptr=(os_timer_t*)param; + timer_ptr = (os_timer_t*)param; } else{ @@ -347,7 +360,7 @@ static void timer_unregister_task(task_param_t param, uint8 priority){ unregister_queue = unregister_queue->next; c_free(queue_temp); if(unregister_queue != NULL){ -// SWTMR_DBG("unregister_queue not empty, posting task"); + SWTMR_DBG("unregister_queue not empty, posting task"); task_post_low(timer_unreg_task_id, false); } } @@ -356,10 +369,10 @@ static void timer_unregister_task(task_param_t param, uint8 priority){ } - os_timer_t** registry_ptr=timer_registry_check(timer_ptr); - if(registry_ptr!=NULL){ + os_timer_t** registry_ptr = timer_registry_check(timer_ptr); + if(registry_ptr != NULL){ if(!dynarr_remove(&timer_registry, registry_ptr)){ - /**/SWTMR_DBG("unable to remove timer(%p) from registry", timer_ptr); + /**/SWTMR_ERR("Failed to remove timer(%p) from registry", timer_ptr); //timer remove FAIL } } @@ -375,37 +388,41 @@ static void timer_unregister_task(task_param_t param, uint8 priority){ 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(); + uint32 time_till_fire = 0; + uint32 time = system_get_time(); timer_registry_remove_unarmed(); - time=system_get_time()-time; + time = system_get_time()-time; /**/SWTMR_DBG("registry_remove_unarmed_timers() took %u us", time); - os_timer_t** timer_array=timer_registry.data_ptr; + 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)"); - c_printf("\n array used(%u)/size(%u)\ttotal size(bytes)=%u\n FRC2 COUNT %u (in ms)\n", - timer_registry.used, timer_registry.array_size, timer_registry.array_size * timer_registry.data_size, (uint32)(frc2_count/312.5)); + 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)); - for(int i=0;itimer_expire/312.5)-(frc2_count/312.5); - c_printf("\ttimer_registry[%u]=%p\ttimer_expire:%u\ttimer_period:%u\ttime till fire:%u\n", i, timer_array[i], (uint32)(timer_array[i]->timer_expire/312.5), (uint32)(timer_array[i]->timer_period/312.5), time_till_fire); } return; } void swtmr_print_suspended(void){ - uint32 period, time_left; 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)); - for(int i=0;itimer_expire/312.5), (uint32)(susp_timer_array[i]->timer_period/312.5)); } return; } @@ -414,9 +431,8 @@ 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; - char print_buffer[2048]; - - c_printf("\n\ttimer_list contents:\ncurrent FRC2 count:%u\n", frc2_count); + 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(); @@ -434,12 +450,13 @@ void swtmr_print_timer_list(void){ 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 sw_timer_suspend(os_timer_t* timer_ptr){ +int swtmr_suspend(os_timer_t* timer_ptr){ int return_value = SWTMR_OK; if(timer_ptr != NULL){ @@ -476,7 +493,7 @@ int sw_timer_suspend(os_timer_t* timer_ptr){ return return_value; } -int sw_timer_resume(os_timer_t* timer_ptr){ +int swtmr_resume(os_timer_t* timer_ptr){ if(suspended_timers.data_ptr == NULL){ return SWTMR_SUSPEND_NO_SUSPENDED_TIMERS; @@ -486,7 +503,7 @@ int sw_timer_resume(os_timer_t* timer_ptr){ os_timer_t** suspended_timer_ptr = NULL; int retval=SWTMR_OK; - if(timer_ptr!=NULL){ + if(timer_ptr != NULL){ suspended_timer_ptr = timer_suspended_check(timer_ptr); if(suspended_timer_ptr == NULL){ //timer not suspended @@ -513,7 +530,7 @@ int sw_timer_resume(os_timer_t* timer_ptr){ return SWTMR_OK; } -void sw_timer_register(void* timer_ptr){ +void swtmr_register(void* timer_ptr){ if(timer_ptr == NULL){ SWTMR_DBG("error: timer_ptr is NULL"); return; @@ -532,7 +549,7 @@ void sw_timer_register(void* timer_ptr){ 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); + SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr); } else{ registry_queue_t* register_queue_tail = register_queue; @@ -542,13 +559,13 @@ void sw_timer_register(void* timer_ptr){ } register_queue_tail->next = queue_temp; -// SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr); + SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr); } return; } -void sw_timer_unregister(void* timer_ptr){ +void swtmr_unregister(void* timer_ptr){ if(timer_ptr == NULL){ SWTMR_DBG("error: timer_ptr is NULL"); return; @@ -566,7 +583,7 @@ void sw_timer_unregister(void* timer_ptr){ 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); + SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr); } else{ registry_queue_t* unregister_queue_tail=unregister_queue; @@ -583,7 +600,7 @@ void sw_timer_unregister(void* timer_ptr){ const char* swtmr_errorcode2str(int error_value){ #ifdef USE_SWTMR_ERROR_STRINGS if(SWTMR_ERROR_STRINGS[error_value] == NULL){ - SWTMR_ERR("ERRORCEPTION!"); + SWTMR_ERR("error string %d not found", error_value); return NULL; } else{ @@ -603,3 +620,5 @@ bool swtmr_suspended_test(os_timer_t* timer_ptr){ } return true; } + +#endif diff --git a/docs/en/modules/node.md b/docs/en/modules/node.md index 3454fad2d0..b21dad5bce 100644 --- a/docs/en/modules/node.md +++ b/docs/en/modules/node.md @@ -123,6 +123,11 @@ node.dsleep(1000000, 4) node.dsleep(nil,4) ``` +#### See also +[`wifi.suspend()`](wifi.md#wifisuspend) +[`wifi.resume()`](wifi.md#wifiresume) +[`node.sleep()`](#nodesleep) + ## node.flashid() Returns the flash chip ID. @@ -315,6 +320,71 @@ target CPU frequency (number) node.setcpufreq(node.CPU80MHZ) ``` + +## node.sleep() + +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. + +#### Syntax +`node.sleep({wake_gpio[, duration, 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. + +#### Returns +- `nil` + +#### Example + +```lua + +--Put NodeMCU in light sleep mode indefinitely with resume callback and wake interrupt + cfg={} + cfg.wake_pin=3 + cfg.resume_cb=function() print("WiFi resume") end + + node.sleep(cfg) + +--Put NodeMCU in light sleep mode with interrupt, resume callback and discard WiFi mode + cfg={} + cfg.wake_pin=3 --GPIO0 + cfg.resume_cb=function() print("WiFi resume") end + cfg.preserve_mode=false + + node.sleep(cfg) + +--Put NodeMCU in light sleep mode for 10 seconds with resume callback + cfg={} + cfg.duration=10*1000*1000 + cfg.resume_cb=function() print("WiFi resume") end + + node.sleep(cfg) + +``` + +#### See also +[`wifi.suspend()`](wifi.md#wifisuspend) +[`wifi.resume()`](wifi.md#wifiresume) +[`node.dsleep()`](#nodedsleep) + ## node.stripdebug() Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code. diff --git a/docs/en/modules/tmr.md b/docs/en/modules/tmr.md index 919682d2f9..13ec13d19d 100644 --- a/docs/en/modules/tmr.md +++ b/docs/en/modules/tmr.md @@ -182,6 +182,61 @@ 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. @@ -279,6 +334,67 @@ if not mytimer:stop() then print("timer not stopped, not registered?") end - [`tmr.stop()`](#tmrstop) - [`tmr.unregister()`](#tmrunregister) +## tmr.suspend() + +Suspend an armed timer. + +* 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. + +!!! 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/docs/en/modules/wifi.md b/docs/en/modules/wifi.md index 861db30456..28b1af7c22 100644 --- a/docs/en/modules/wifi.md +++ b/docs/en/modules/wifi.md @@ -74,6 +74,37 @@ The current physical mode as one of `wifi.PHYMODE_B`, `wifi.PHYMODE_G` or `wifi. #### See also [`wifi.setphymode()`](#wifisetphymode) +## wifi.resume() + +Wake up WiFi from suspended state or cancel pending wifi suspension + +#### Syntax +`wifi.resume([resume_cb])` + +#### Parameters +- `resume_cb` Callback to execute when WiFi wakes from suspension. + !!! note "Note:" + + Any previously provided callbacks will be replaced! + +#### Returns +`nil` + +#### Example + +```lua +--Resume wifi from timed or indefinite sleep +wifi.resume() + +--Resume wifi from timed or indefinite sleep w/ resume callback +wifi.resume(function() print("WiFi resume") end) +``` + +#### See also +[`wifi.suspend()`](#wifisuspend) +[`node.sleep()`](node.md#nodesleep) +[`node.dsleep()`](node.md#nodedsleep) + ## wifi.setmode() Configures the WiFi mode to use. NodeMCU can run in one of four WiFi modes: @@ -221,6 +252,61 @@ none #### See also [`wifi.startsmart()`](#wifistartsmart) +## wifi.suspend() + +Suspend Wifi to reduce current consumption. + +This function is also useful for preventing WiFi stack related crashes when executing functions or tasks that take longer than ~500ms + +#### Syntax +`wifi.suspend({duration[, suspend_cb, resume_cb, preserve_mode]})` + +#### Parameters +- `duration` Suspend duration in microseconds(μs). If a suspend duration of `0` is specified, suspension will be indefinite (Range: 0 or 50000 - 268435454 μs (0:4:28.000454)) +- `suspend_cb` Callback to execute when WiFi is suspended. (Optional) +- `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`](#wifigetmode). WiFi mode will be restored to original mode on restart. + +#### Returns +- `suspend_state` if no parameters are provided, current WiFi suspension state will be returned + - States: + - `0` WiFi is awake. + - `1` WiFi suspension is pending. (Waiting for idle task) + - `2` WiFi is suspended. + + +#### Example + +```lua +--get current wifi suspension state +print(wifi.suspend()) + +--Suspend WiFi for 10 seconds with suspend/resume callbacks + cfg={} + cfg.duration=10*1000*1000 + cfg.resume_cb=function() print("WiFi resume") end + cfg.suspend_cb=function() print("WiFi suspended") end + + wifi.suspend(cfg) + +--Suspend WiFi for 10 seconds with suspend/resume callbacks and discard WiFi mode + cfg={} + cfg.duration=10*1000*1000 + cfg.resume_cb=function() print("WiFi resume") end + cfg.suspend_cb=function() print("WiFfi suspended") end + cfg.preserve_mode=false + + wifi.suspend(cfg) + +``` + +#### See also +[`wifi.resume()`](#wifiresume) +[`node.sleep()`](node.md#nodesleep) +[`node.dsleep()`](node.md#nodedsleep) + # wifi.sta Module ## wifi.sta.autoconnect() @@ -985,7 +1071,7 @@ number: 0~5 ## wifi.ap.config() -Sets SSID and password in AP mode. Be sure to make the password at least 8 characters long! If you don't it will default to *no* password and not set the SSID! It will still work as an access point but use a default SSID like e.g. NODE-9997C3. +Sets SSID and password in AP mode. Be sure to make the password at least 8 characters long! If you don't it will default to *no* password and not set the SSID! It will still work as an access point but use a default SSID like e.g. NODE_9997C3. #### Syntax `wifi.ap.config(cfg)` diff --git a/sdk-overrides/include/ets_sys.h b/sdk-overrides/include/ets_sys.h index fcfd28723e..eb4cf80d29 100644 --- a/sdk-overrides/include/ets_sys.h +++ b/sdk-overrides/include/ets_sys.h @@ -11,5 +11,4 @@ int ets_vsprintf (char *d, const char *s, va_list ap); extern ETSTimer *timer_list; - #endif /* SDK_OVERRIDES_INCLUDE_ETS_SYS_H_ */ diff --git a/sdk-overrides/include/osapi.h b/sdk-overrides/include/osapi.h index b90d25972e..46b797f2ba 100644 --- a/sdk-overrides/include/osapi.h +++ b/sdk-overrides/include/osapi.h @@ -16,14 +16,15 @@ void call_user_start(void); #include_next "osapi.h" -extern void sw_timer_register(void* timer_ptr); +#ifdef ENABLE_TIMER_SUSPEND +extern void swtmr_register(void* timer_ptr); #undef os_timer_arm -#define os_timer_arm(timer_ptr, duration, mode) do{sw_timer_register(timer_ptr); \ +#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 sw_timer_unregister(void* timer_ptr); +extern void swtmr_unregister(void* timer_ptr); #undef os_timer_disarm -#define os_timer_disarm(timer_ptr) do{sw_timer_unregister(timer_ptr); ets_timer_disarm(timer_ptr);}while(0); - +#define os_timer_disarm(timer_ptr) do{swtmr_unregister(timer_ptr); ets_timer_disarm(timer_ptr);}while(0); +#endif #endif diff --git a/sdk-overrides/include/user_interface.h b/sdk-overrides/include/user_interface.h index 61ce83568d..9bf2af0c1b 100644 --- a/sdk-overrides/include/user_interface.h +++ b/sdk-overrides/include/user_interface.h @@ -13,4 +13,13 @@ enum ext_flash_size_map { }; +//force sleep API +#define FPM_SLEEP_MAX_TIME 268435455 //0xFFFFFFF +void wifi_fpm_set_wakeup_cb(void (*fpm_wakeup_cb_func)(void)); +bool fpm_is_open(void); +bool fpm_rf_is_closed(void); +uint8 get_fpm_auto_sleep_flag(void); + + + #endif /* SDK_OVERRIDES_INCLUDE_USER_INTERFACE_H_ */