Add wifi.suspend() and node.sleep() (#1231)
* Exposed forced sleep API and more Added timer suspend functionality * wifi.suspend * wifi.resume * node.sleep * tmr.suspend * tmr.suspend_all * tmr.resume * tmr.resume_all * Implement timer suspend functionality * Fix for uart TX glitch * Made some modifications to the error reporting
This commit is contained in:
parent
176443c07f
commit
41a5736d78
10
app/Makefile
10
app/Makefile
|
@ -45,7 +45,11 @@ SUBDIRS= \
|
||||||
http \
|
http \
|
||||||
fatfs \
|
fatfs \
|
||||||
esp-gdbstub \
|
esp-gdbstub \
|
||||||
websocket
|
websocket \
|
||||||
|
swTimer \
|
||||||
|
misc \
|
||||||
|
pm \
|
||||||
|
|
||||||
|
|
||||||
endif # } PDIR
|
endif # } PDIR
|
||||||
|
|
||||||
|
@ -90,11 +94,15 @@ COMPONENTS_eagle.app.v6 = \
|
||||||
dhtlib/libdhtlib.a \
|
dhtlib/libdhtlib.a \
|
||||||
tsl2561/tsl2561lib.a \
|
tsl2561/tsl2561lib.a \
|
||||||
http/libhttp.a \
|
http/libhttp.a \
|
||||||
|
pm/libpm.a \
|
||||||
websocket/libwebsocket.a \
|
websocket/libwebsocket.a \
|
||||||
esp-gdbstub/libgdbstub.a \
|
esp-gdbstub/libgdbstub.a \
|
||||||
net/libnodemcu_net.a \
|
net/libnodemcu_net.a \
|
||||||
mbedtls/libmbedtls.a \
|
mbedtls/libmbedtls.a \
|
||||||
modules/libmodules.a \
|
modules/libmodules.a \
|
||||||
|
swTimer/libswtimer.a \
|
||||||
|
misc/libmisc.a \
|
||||||
|
|
||||||
|
|
||||||
# Inspect the modules library and work out which modules need to be linked.
|
# Inspect the modules library and work out which modules need to be linked.
|
||||||
# For each enabled module, a symbol name of the form XYZ_module_selected is
|
# For each enabled module, a symbol name of the form XYZ_module_selected is
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#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__
|
|
@ -0,0 +1,53 @@
|
||||||
|
#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__
|
|
@ -116,6 +116,10 @@ extern void luaL_assertfail(const char *file, int line, const char *message);
|
||||||
#define WIFI_SDK_EVENT_MONITOR_ENABLE
|
#define WIFI_SDK_EVENT_MONITOR_ENABLE
|
||||||
#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
|
#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
|
||||||
|
|
||||||
|
#define ENABLE_TIMER_SUSPEND
|
||||||
|
#define PMSLEEP_ENABLE
|
||||||
|
|
||||||
|
|
||||||
#define STRBUF_DEFAULT_INCREMENT 32
|
#define STRBUF_DEFAULT_INCREMENT 32
|
||||||
|
|
||||||
#endif /* __USER_CONFIG_H__ */
|
#endif /* __USER_CONFIG_H__ */
|
||||||
|
|
|
@ -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 = 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
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ INCLUDES += -I ../fatfs
|
||||||
INCLUDES += -I ../http
|
INCLUDES += -I ../http
|
||||||
INCLUDES += -I ../sjson
|
INCLUDES += -I ../sjson
|
||||||
INCLUDES += -I ../websocket
|
INCLUDES += -I ../websocket
|
||||||
|
INCLUDES += -I ../pm
|
||||||
PDIR := ../$(PDIR)
|
PDIR := ../$(PDIR)
|
||||||
sinclude $(PDIR)Makefile
|
sinclude $(PDIR)Makefile
|
||||||
|
|
||||||
|
|
|
@ -74,19 +74,36 @@ static int node_deepsleep( lua_State* L )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua: dsleep_set_options
|
|
||||||
// Combined to dsleep( us, option )
|
#ifdef PMSLEEP_ENABLE
|
||||||
// static int node_deepsleep_setoption( lua_State* L )
|
#include "pmSleep.h"
|
||||||
// {
|
|
||||||
// s32 option;
|
int node_sleep_resume_cb_ref= LUA_NOREF;
|
||||||
// option = luaL_checkinteger( L, 1 );
|
void node_sleep_resume_cb(void)
|
||||||
// if ( option < 0 || option > 4)
|
{
|
||||||
// return luaL_error( L, "wrong arg range" );
|
PMSLEEP_DBG("START");
|
||||||
// else
|
pmSleep_execute_lua_cb(&node_sleep_resume_cb_ref);
|
||||||
// deep_sleep_set_option( option );
|
PMSLEEP_DBG("END");
|
||||||
// return 0;
|
}
|
||||||
// }
|
|
||||||
// Lua: info()
|
// 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 )
|
static int node_info( lua_State* L )
|
||||||
{
|
{
|
||||||
|
@ -570,6 +587,10 @@ static const LUA_REG_TYPE node_map[] =
|
||||||
{
|
{
|
||||||
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
|
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
|
||||||
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
|
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
|
||||||
|
#ifdef PMSLEEP_ENABLE
|
||||||
|
{ LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) },
|
||||||
|
PMSLEEP_INT_MAP,
|
||||||
|
#endif
|
||||||
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) },
|
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) },
|
||||||
{ LSTRKEY( "chipid" ), LFUNCVAL( node_chipid ) },
|
{ LSTRKEY( "chipid" ), LFUNCVAL( node_chipid ) },
|
||||||
{ LSTRKEY( "flashid" ), LFUNCVAL( node_flashid ) },
|
{ LSTRKEY( "flashid" ), LFUNCVAL( node_flashid ) },
|
||||||
|
|
|
@ -53,12 +53,14 @@ tmr.softwd(int)
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "c_types.h"
|
#include "c_types.h"
|
||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
|
#include "swTimer/swTimer.h"
|
||||||
|
|
||||||
#define TIMER_MODE_OFF 3
|
#define TIMER_MODE_OFF 3
|
||||||
#define TIMER_MODE_SINGLE 0
|
#define TIMER_MODE_SINGLE 0
|
||||||
#define TIMER_MODE_SEMI 2
|
#define TIMER_MODE_SEMI 2
|
||||||
#define TIMER_MODE_AUTO 1
|
#define TIMER_MODE_AUTO 1
|
||||||
#define TIMER_IDLE_FLAG (1<<7)
|
#define TIMER_IDLE_FLAG (1<<7)
|
||||||
|
|
||||||
|
|
||||||
#define STRINGIFY_VAL(x) #x
|
#define STRINGIFY_VAL(x) #x
|
||||||
#define STRINGIFY(x) STRINGIFY_VAL(x)
|
#define STRINGIFY(x) STRINGIFY_VAL(x)
|
||||||
|
@ -172,14 +174,14 @@ static int tmr_register(lua_State* L){
|
||||||
lua_pushvalue(L, 4);
|
lua_pushvalue(L, 4);
|
||||||
sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
|
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
|
||||||
ets_timer_disarm(&tmr->os);
|
os_timer_disarm(&tmr->os);
|
||||||
//there was a bug in this part, the second part of the following condition was missing
|
//there was a bug in this part, the second part of the following condition was missing
|
||||||
if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
|
if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
|
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
|
||||||
tmr->lua_ref = ref;
|
tmr->lua_ref = ref;
|
||||||
tmr->mode = mode|TIMER_IDLE_FLAG;
|
tmr->mode = mode|TIMER_IDLE_FLAG;
|
||||||
tmr->interval = interval;
|
tmr->interval = interval;
|
||||||
ets_timer_setfn(&tmr->os, alarm_timer_common, tmr);
|
os_timer_setfn(&tmr->os, alarm_timer_common, tmr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +199,7 @@ static int tmr_start(lua_State* L){
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
}else{
|
}else{
|
||||||
tmr->mode &= ~TIMER_IDLE_FLAG;
|
tmr->mode &= ~TIMER_IDLE_FLAG;
|
||||||
ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
|
os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -221,7 +223,7 @@ static int tmr_stop(lua_State* L){
|
||||||
//we return false if the timer is idle (of not registered)
|
//we return false if the timer is idle (of not registered)
|
||||||
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
|
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
|
||||||
tmr->mode |= TIMER_IDLE_FLAG;
|
tmr->mode |= TIMER_IDLE_FLAG;
|
||||||
ets_timer_disarm(&tmr->os);
|
os_timer_disarm(&tmr->os);
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
}else{
|
}else{
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
|
@ -229,6 +231,73 @@ static int tmr_stop(lua_State* L){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_TIMER_SUSPEND
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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 )
|
// Lua: tmr.unregister( id / ref )
|
||||||
static int tmr_unregister(lua_State* L){
|
static int tmr_unregister(lua_State* L){
|
||||||
timer_t tmr = tmr_get(L, 1);
|
timer_t tmr = tmr_get(L, 1);
|
||||||
|
@ -239,7 +308,7 @@ static int tmr_unregister(lua_State* L){
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
|
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
|
||||||
ets_timer_disarm(&tmr->os);
|
os_timer_disarm(&tmr->os);
|
||||||
if(tmr->lua_ref != LUA_NOREF)
|
if(tmr->lua_ref != LUA_NOREF)
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
|
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
|
||||||
tmr->lua_ref = LUA_NOREF;
|
tmr->lua_ref = LUA_NOREF;
|
||||||
|
@ -256,8 +325,8 @@ static int tmr_interval(lua_State* L){
|
||||||
if(tmr->mode != TIMER_MODE_OFF){
|
if(tmr->mode != TIMER_MODE_OFF){
|
||||||
tmr->interval = interval;
|
tmr->interval = interval;
|
||||||
if(!(tmr->mode&TIMER_IDLE_FLAG)){
|
if(!(tmr->mode&TIMER_IDLE_FLAG)){
|
||||||
ets_timer_disarm(&tmr->os);
|
os_timer_disarm(&tmr->os);
|
||||||
ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
|
os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -271,9 +340,15 @@ static int tmr_state(lua_State* L){
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
lua_pushboolean(L, (tmr->mode&TIMER_IDLE_FLAG)==0);
|
|
||||||
lua_pushinteger(L, tmr->mode&(~TIMER_IDLE_FLAG));
|
lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
|
||||||
return 2;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*I left the led comments 'couse I don't know
|
/*I left the led comments 'couse I don't know
|
||||||
|
@ -348,10 +423,27 @@ static int tmr_create( lua_State *L ) {
|
||||||
ud->lua_ref = LUA_NOREF;
|
ud->lua_ref = LUA_NOREF;
|
||||||
ud->self_ref = LUA_NOREF;
|
ud->self_ref = LUA_NOREF;
|
||||||
ud->mode = TIMER_MODE_OFF;
|
ud->mode = TIMER_MODE_OFF;
|
||||||
ets_timer_disarm(&ud->os);
|
os_timer_disarm(&ud->os);
|
||||||
return 1;
|
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
|
// Module function map
|
||||||
|
|
||||||
static const LUA_REG_TYPE tmr_dyn_map[] = {
|
static const LUA_REG_TYPE tmr_dyn_map[] = {
|
||||||
|
@ -362,11 +454,24 @@ static const LUA_REG_TYPE tmr_dyn_map[] = {
|
||||||
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
|
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
|
||||||
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
|
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
|
||||||
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
|
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
|
||||||
|
#ifdef ENABLE_TIMER_SUSPEND
|
||||||
|
{ LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
|
||||||
|
{ LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
|
||||||
|
#endif
|
||||||
{ LSTRKEY( "__gc" ), LFUNCVAL( tmr_unregister ) },
|
{ LSTRKEY( "__gc" ), LFUNCVAL( tmr_unregister ) },
|
||||||
{ LSTRKEY( "__index" ), LROVAL( tmr_dyn_map ) },
|
{ LSTRKEY( "__index" ), LROVAL( tmr_dyn_map ) },
|
||||||
{ LNILKEY, LNILVAL }
|
{ 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[] = {
|
static const LUA_REG_TYPE tmr_map[] = {
|
||||||
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
|
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
|
||||||
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
|
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
|
||||||
|
@ -376,11 +481,20 @@ static const LUA_REG_TYPE tmr_map[] = {
|
||||||
{ LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
|
{ LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
|
||||||
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
|
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
|
||||||
{ LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
|
{ LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
|
||||||
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
|
{ 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( "unregister" ), LFUNCVAL( tmr_unregister ) },
|
||||||
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
|
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
|
||||||
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) },
|
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) },
|
||||||
{ LSTRKEY( "create" ), LFUNCVAL( tmr_create ) },
|
{ 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_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
|
||||||
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
|
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
|
||||||
{ LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
|
{ LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
|
||||||
|
@ -396,14 +510,16 @@ int luaopen_tmr( lua_State *L ){
|
||||||
alarm_timers[i].lua_ref = LUA_NOREF;
|
alarm_timers[i].lua_ref = LUA_NOREF;
|
||||||
alarm_timers[i].self_ref = LUA_REFNIL;
|
alarm_timers[i].self_ref = LUA_REFNIL;
|
||||||
alarm_timers[i].mode = TIMER_MODE_OFF;
|
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);
|
ets_timer_disarm(&alarm_timers[i].os);
|
||||||
}
|
}
|
||||||
last_rtc_time=system_get_rtc_time(); // Right now is time 0
|
last_rtc_time=system_get_rtc_time(); // Right now is time 0
|
||||||
last_rtc_time_us=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);
|
ets_timer_disarm(&rtc_timer);
|
||||||
ets_timer_setfn(&rtc_timer, rtc_callback, NULL);
|
os_timer_setfn(&rtc_timer, rtc_callback, NULL);
|
||||||
ets_timer_arm_new(&rtc_timer, 1000, 1, 1);
|
os_timer_arm(&rtc_timer, 1000, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,6 @@ static uint8 getap_output_format=0;
|
||||||
|
|
||||||
#define INVALID_MAC_STR "MAC:FF:FF:FF:FF:FF:FF"
|
#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
|
#ifdef WIFI_SMART_ENABLE
|
||||||
static void wifi_smart_succeed_cb(sc_status status, void *pdata){
|
static void wifi_smart_succeed_cb(sc_status status, void *pdata){
|
||||||
NODE_DBG("wifi_smart_succeed_cb is called.\n");
|
NODE_DBG("wifi_smart_succeed_cb is called.\n");
|
||||||
|
@ -302,66 +298,92 @@ static int wifi_getphymode( lua_State* L )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua: wifi.sleep()
|
#ifdef PMSLEEP_ENABLE
|
||||||
static int wifi_sleep(lua_State* L)
|
/* Begin WiFi suspend functions*/
|
||||||
{
|
#include "pmSleep.h"
|
||||||
uint8 desired_sleep_state = 2;
|
|
||||||
sint8 wifi_fpm_do_sleep_return_value = 1;
|
|
||||||
if(lua_isnumber(L, 1))
|
|
||||||
{
|
|
||||||
if(luaL_checknumber(L, 1) == 0)
|
|
||||||
{
|
|
||||||
desired_sleep_state = 0;
|
|
||||||
}
|
|
||||||
else if(luaL_checknumber(L, 1) == 1)
|
|
||||||
{
|
|
||||||
desired_sleep_state = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!FLAG_wifi_force_sleep_enabled && desired_sleep_state == 1)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
FLAG_wifi_force_sleep_enabled = FALSE;
|
|
||||||
// wake up to use WiFi again
|
|
||||||
wifi_fpm_do_wakeup();
|
|
||||||
wifi_fpm_close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired_sleep_state == 1 && FLAG_wifi_force_sleep_enabled == FALSE)
|
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)
|
||||||
|
{
|
||||||
|
PMSLEEP_DBG("\n\tDBG: %s start\n", __func__);
|
||||||
|
if (wifi_suspend_cb_ref != LUA_NOREF)
|
||||||
{
|
{
|
||||||
lua_pushnil(L);
|
lua_State* L = lua_getstate(); // Get main Lua thread pointer
|
||||||
lua_pushnumber(L, wifi_fpm_do_sleep_return_value);
|
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
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lua_pushnumber(L, FLAG_wifi_force_sleep_enabled);
|
PMSLEEP_DBG("\n\tDBG: lua cb unavailable\n");
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
}
|
||||||
return 2;
|
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))
|
||||||
|
{
|
||||||
|
// Return current WiFi suspension state
|
||||||
|
lua_pushnumber(L, pmSleep_get_state());
|
||||||
|
return 1; // Return WiFi suspension state
|
||||||
|
}
|
||||||
|
|
||||||
|
pmSleep_INIT_CFG(cfg);
|
||||||
|
cfg.sleep_mode = MODEM_SLEEP_T;
|
||||||
|
if(lua_istable(L, 1))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return luaL_error(L, "WIFi not suspended");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
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()
|
// Lua: wifi.nullmodesleep()
|
||||||
static int wifi_null_mode_auto_sleep(lua_State* L)
|
static int wifi_null_mode_auto_sleep(lua_State* L)
|
||||||
{
|
{
|
||||||
|
@ -1659,7 +1681,10 @@ static const LUA_REG_TYPE wifi_map[] = {
|
||||||
{ LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) },
|
{ LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) },
|
||||||
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
|
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
|
||||||
{ LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) },
|
{ 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 ) },
|
{ LSTRKEY( "nullmodesleep" ), LFUNCVAL( wifi_null_mode_auto_sleep ) },
|
||||||
#ifdef WIFI_SMART_ENABLE
|
#ifdef WIFI_SMART_ENABLE
|
||||||
{ LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) },
|
{ LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) },
|
||||||
|
|
|
@ -52,6 +52,15 @@ void wifi_change_default_host_name(void);
|
||||||
#define EVENT_DBG(...) //c_printf(__VA_ARGS__)
|
#define EVENT_DBG(...) //c_printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum wifi_suspension_state
|
||||||
|
{
|
||||||
|
WIFI_AWAKE = 0,
|
||||||
|
WIFI_SUSPENSION_PENDING = 1,
|
||||||
|
WIFI_SUSPENDED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIFI_SDK_EVENT_MONITOR_ENABLE
|
#ifdef WIFI_SDK_EVENT_MONITOR_ENABLE
|
||||||
extern const LUA_REG_TYPE wifi_event_monitor_map[];
|
extern const LUA_REG_TYPE wifi_event_monitor_map[];
|
||||||
void wifi_eventmon_init();
|
void wifi_eventmon_init();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,381 @@
|
||||||
|
#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 suspend_all_timers(void);
|
||||||
|
static void null_mode_check_timer_cb(void* arg);
|
||||||
|
static void resume_all_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 suspend_all_timers(void){
|
||||||
|
#ifdef ENABLE_TIMER_SUSPEND
|
||||||
|
swtmr_suspend(NULL);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resume_all_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){
|
||||||
|
//check if uart 0 tx buffer is empty and uart 1 tx buffer is empty
|
||||||
|
if(current_config.sleep_mode == LIGHT_SLEEP_T){
|
||||||
|
if((READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S)) == 0 &&
|
||||||
|
(READ_PERI_REG(UART_STATUS(1)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S)) == 0){
|
||||||
|
ets_timer_disarm(&null_mode_check_timer);
|
||||||
|
suspend_all_timers();
|
||||||
|
//Ensure UART 0/1 TX FIFO is clear
|
||||||
|
SET_PERI_REG_MASK(UART_CONF0(0), UART_TXFIFO_RST);//RESET FIFO
|
||||||
|
CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_TXFIFO_RST);
|
||||||
|
SET_PERI_REG_MASK(UART_CONF0(1), UART_TXFIFO_RST);//RESET FIFO
|
||||||
|
CLEAR_PERI_REG_MASK(UART_CONF0(1), UART_TXFIFO_RST);
|
||||||
|
wifi_fpm_do_sleep(current_config.sleep_duration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{ //MODEM_SLEEP_T
|
||||||
|
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();
|
||||||
|
PMSLEEP_ERR("wifi_fpm_do_sleep returned %d", retval_wifi_fpm_do_sleep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ets_timer_disarm(&null_mode_check_timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//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");
|
||||||
|
|
||||||
|
resume_all_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));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
PMSLEEP_ERR("opmode change fail");
|
||||||
|
}
|
||||||
|
PMSLEEP_DBG("END");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,69 @@
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#if defined(DEVELOP_VERSION)
|
||||||
|
#define PMSLEEP_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PMSLEEP_DEBUG)
|
||||||
|
#define PMSLEEP_DBG(fmt, ...) dbg_printf("\tPMSLEEP(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define PMSLEEP_DBG(...) //c_printf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NODE_ERROR)
|
||||||
|
#define PMSLEEP_ERR(fmt, ...) NODE_ERR("%s"fmt"\n", "PMSLEEP:", ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define PMSLEEP_ERR(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#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 ) }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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__
|
|
@ -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 = 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
|
||||||
|
|
|
@ -0,0 +1,632 @@
|
||||||
|
/* 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
|
|
@ -127,6 +127,11 @@ node.dsleep(1000000, 4)
|
||||||
node.dsleep(nil,4)
|
node.dsleep(nil,4)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### See also
|
||||||
|
[`wifi.suspend()`](wifi.md#wifisuspend)
|
||||||
|
[`wifi.resume()`](wifi.md#wifiresume)
|
||||||
|
[`node.sleep()`](#nodesleep)
|
||||||
|
|
||||||
## node.flashid()
|
## node.flashid()
|
||||||
|
|
||||||
Returns the flash chip ID.
|
Returns the flash chip ID.
|
||||||
|
@ -321,6 +326,71 @@ target CPU frequency (number)
|
||||||
node.setcpufreq(node.CPU80MHZ)
|
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()
|
## node.stripdebug()
|
||||||
|
|
||||||
Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code.
|
Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code.
|
||||||
|
|
|
@ -62,9 +62,11 @@ Functions supported in timer object:
|
||||||
- [`t:alarm()`](#tmralarm)
|
- [`t:alarm()`](#tmralarm)
|
||||||
- [`t:interval()`](#tmrinterval)
|
- [`t:interval()`](#tmrinterval)
|
||||||
- [`t:register()`](#tmrregister)
|
- [`t:register()`](#tmrregister)
|
||||||
|
- [`t:resume()`](#tmrresume)
|
||||||
- [`t:start()`](#tmrstart)
|
- [`t:start()`](#tmrstart)
|
||||||
- [`t:state()`](#tmrstate)
|
- [`t:state()`](#tmrstate)
|
||||||
- [`t:stop()`](#tmrstop)
|
- [`t:stop()`](#tmrstop)
|
||||||
|
- [`t:suspend()`](#tmrsuspend)
|
||||||
- [`t:unregister()`](#tmrunregister)
|
- [`t:unregister()`](#tmrunregister)
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
@ -182,6 +184,61 @@ mytimer:start()
|
||||||
- [`tmr.create()`](#tmrcreate)
|
- [`tmr.create()`](#tmrcreate)
|
||||||
- [`tmr.alarm()`](#tmralarm)
|
- [`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()
|
## tmr.softwd()
|
||||||
|
|
||||||
Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted.
|
Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted.
|
||||||
|
@ -279,6 +336,67 @@ if not mytimer:stop() then print("timer not stopped, not registered?") end
|
||||||
- [`tmr.stop()`](#tmrstop)
|
- [`tmr.stop()`](#tmrstop)
|
||||||
- [`tmr.unregister()`](#tmrunregister)
|
- [`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()
|
## tmr.time()
|
||||||
|
|
||||||
Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero.
|
Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero.
|
||||||
|
|
|
@ -74,6 +74,37 @@ The current physical mode as one of `wifi.PHYMODE_B`, `wifi.PHYMODE_G` or `wifi.
|
||||||
#### See also
|
#### See also
|
||||||
[`wifi.setphymode()`](#wifisetphymode)
|
[`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()
|
## wifi.setmode()
|
||||||
|
|
||||||
Configures the WiFi mode to use. NodeMCU can run in one of four WiFi modes:
|
Configures the WiFi mode to use. NodeMCU can run in one of four WiFi modes:
|
||||||
|
@ -222,6 +253,61 @@ none
|
||||||
#### See also
|
#### See also
|
||||||
[`wifi.startsmart()`](#wifistartsmart)
|
[`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 Module
|
||||||
|
|
||||||
## wifi.sta.autoconnect()
|
## wifi.sta.autoconnect()
|
||||||
|
@ -1010,7 +1096,7 @@ The current state which can be one of the following:
|
||||||
|
|
||||||
## wifi.ap.config()
|
## 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
|
#### Syntax
|
||||||
`wifi.ap.config(cfg)`
|
`wifi.ap.config(cfg)`
|
||||||
|
|
|
@ -9,4 +9,6 @@ int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (pri
|
||||||
|
|
||||||
int ets_vsprintf (char *d, const char *s, va_list ap);
|
int ets_vsprintf (char *d, const char *s, va_list ap);
|
||||||
|
|
||||||
|
extern ETSTimer *timer_list;
|
||||||
|
|
||||||
#endif /* SDK_OVERRIDES_INCLUDE_ETS_SYS_H_ */
|
#endif /* SDK_OVERRIDES_INCLUDE_ETS_SYS_H_ */
|
||||||
|
|
|
@ -16,4 +16,15 @@ void call_user_start(void);
|
||||||
|
|
||||||
#include_next "osapi.h"
|
#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
|
#endif
|
||||||
|
|
|
@ -15,4 +15,13 @@ enum ext_flash_size_map {
|
||||||
// Documented in section 4.5 of 9b-esp8266_low_power_solutions_en.pdf
|
// Documented in section 4.5 of 9b-esp8266_low_power_solutions_en.pdf
|
||||||
void system_deep_sleep_instant(uint32 time_in_us);
|
void system_deep_sleep_instant(uint32 time_in_us);
|
||||||
|
|
||||||
|
//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_ */
|
#endif /* SDK_OVERRIDES_INCLUDE_USER_INTERFACE_H_ */
|
||||||
|
|
Loading…
Reference in New Issue