Unverified Commit 8b84445a authored by Terry Ellison's avatar Terry Ellison Committed by GitHub
Browse files

Merge pull request #2391 from nodemcu/dev

Next master snap
parents 67027c0d 2cc195d5
#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;
}
...@@ -190,7 +190,7 @@ static void cron_handle_tmr() { ...@@ -190,7 +190,7 @@ static void cron_handle_tmr() {
struct rtc_timeval tv; struct rtc_timeval tv;
rtctime_gettimeofday(&tv); rtctime_gettimeofday(&tv);
if (tv.tv_sec == 0) { // Wait for RTC time if (tv.tv_sec == 0) { // Wait for RTC time
ets_timer_arm_new(&cron_timer, 1000, 0, 1); os_timer_arm(&cron_timer, 1000, 0);
return; return;
} }
time_t t = tv.tv_sec; time_t t = tv.tv_sec;
...@@ -202,7 +202,7 @@ static void cron_handle_tmr() { ...@@ -202,7 +202,7 @@ static void cron_handle_tmr() {
diff += 60000; diff += 60000;
gmtime_r(&t, &tm); gmtime_r(&t, &tm);
} }
ets_timer_arm_new(&cron_timer, diff, 0, 1); os_timer_arm(&cron_timer, diff, 0);
cron_handle_time(tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, tm.tm_hour, tm.tm_min); cron_handle_time(tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, tm.tm_hour, tm.tm_min);
} }
...@@ -220,11 +220,15 @@ static const LUA_REG_TYPE cron_map[] = { ...@@ -220,11 +220,15 @@ static const LUA_REG_TYPE cron_map[] = {
{ LSTRKEY( "reset" ), LFUNCVAL( lcron_reset ) }, { LSTRKEY( "reset" ), LFUNCVAL( lcron_reset ) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
#include "pm/swtimer.h"
int luaopen_cron( lua_State *L ) { int luaopen_cron( lua_State *L ) {
ets_timer_disarm(&cron_timer); os_timer_disarm(&cron_timer);
ets_timer_setfn(&cron_timer, cron_handle_tmr, 0); os_timer_setfn(&cron_timer, cron_handle_tmr, 0);
ets_timer_arm_new(&cron_timer, 1000, 0, 1); SWTIMER_REG_CB(cron_handle_tmr, SWTIMER_RESTART);
//cron_handle_tmr determines when to execute a scheduled cron job
//My guess: To be sure to give the other modules required by cron enough time to get to a ready state, restart cron_timer.
os_timer_arm(&cron_timer, 1000, 0);
luaL_rometatable(L, "cron.entry", (void *)cronent_map); luaL_rometatable(L, "cron.entry", (void *)cronent_map);
return 0; return 0;
} }
......
...@@ -134,6 +134,8 @@ static int ds18b20_lua_setting(lua_State *L) { ...@@ -134,6 +134,8 @@ static int ds18b20_lua_setting(lua_State *L) {
return 0; return 0;
} }
#include "pm/swtimer.h"
// Reads sensor values from all devices // Reads sensor values from all devices
// Lua: ds18b20.read(function(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) print(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) end, ROM[, FAMILY]) // Lua: ds18b20.read(function(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) print(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) end, ROM[, FAMILY])
static int ds18b20_lua_read(lua_State *L) { static int ds18b20_lua_read(lua_State *L) {
...@@ -173,6 +175,9 @@ static int ds18b20_lua_read(lua_State *L) { ...@@ -173,6 +175,9 @@ static int ds18b20_lua_read(lua_State *L) {
onewire_write(ds18b20_bus_pin, DS18B20_ROM_SKIP, 0); onewire_write(ds18b20_bus_pin, DS18B20_ROM_SKIP, 0);
onewire_write(ds18b20_bus_pin, DS18B20_FUNC_CONVERT, 1); onewire_write(ds18b20_bus_pin, DS18B20_FUNC_CONVERT, 1);
os_timer_setfn(&ds18b20_timer, (os_timer_func_t *)ds18b20_lua_readoutdone, NULL); os_timer_setfn(&ds18b20_timer, (os_timer_func_t *)ds18b20_lua_readoutdone, NULL);
SWTIMER_REG_CB(ds18b20_lua_readoutdone, SWTIMER_DROP);
//The function ds18b20_lua_readoutdone reads the temperature from the sensor(s) after a set amount of time depending on temperature resolution
//MY guess: If this timer manages to get suspended before it fires and the temperature data is time sensitive then resulting data would be invalid and should be discarded
switch (ds18b20_device_res) { switch (ds18b20_device_res) {
case (9): case (9):
...@@ -192,6 +197,7 @@ static int ds18b20_lua_read(lua_State *L) { ...@@ -192,6 +197,7 @@ static int ds18b20_lua_read(lua_State *L) {
static int ds18b20_read_device(uint8_t *ds18b20_device_rom) { static int ds18b20_read_device(uint8_t *ds18b20_device_rom) {
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
int16_t ds18b20_raw_temp;
if (onewire_crc8(ds18b20_device_rom,7) == ds18b20_device_rom[7]) { if (onewire_crc8(ds18b20_device_rom,7) == ds18b20_device_rom[7]) {
...@@ -216,8 +222,9 @@ static int ds18b20_read_device(uint8_t *ds18b20_device_rom) { ...@@ -216,8 +222,9 @@ static int ds18b20_read_device(uint8_t *ds18b20_device_rom) {
lua_pushfstring(L, "%d:%d:%d:%d:%d:%d:%d:%d", ds18b20_device_rom[0], ds18b20_device_rom[1], ds18b20_device_rom[2], ds18b20_device_rom[3], ds18b20_device_rom[4], ds18b20_device_rom[5], ds18b20_device_rom[6], ds18b20_device_rom[7]); lua_pushfstring(L, "%d:%d:%d:%d:%d:%d:%d:%d", ds18b20_device_rom[0], ds18b20_device_rom[1], ds18b20_device_rom[2], ds18b20_device_rom[3], ds18b20_device_rom[4], ds18b20_device_rom[5], ds18b20_device_rom[6], ds18b20_device_rom[7]);
ds18b20_device_scratchpad_conf = (ds18b20_device_scratchpad[4] >> 5) + 9; ds18b20_device_scratchpad_conf = (ds18b20_device_scratchpad[4] >> 5) + 9;
ds18b20_device_scratchpad_temp = ((int8_t)(ds18b20_device_scratchpad[1] << 4) + (ds18b20_device_scratchpad[0] >> 4) + ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16)); ds18b20_raw_temp = ((ds18b20_device_scratchpad[1] << 8) | ds18b20_device_scratchpad[0]);
ds18b20_device_scratchpad_temp_dec = ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16 * 1000); ds18b20_device_scratchpad_temp = (double)ds18b20_raw_temp / 16;
ds18b20_device_scratchpad_temp_dec = (ds18b20_raw_temp - (ds18b20_raw_temp / 16 * 16)) * 1000 / 16;
if (ds18b20_device_scratchpad_conf >= ds18b20_device_res) { if (ds18b20_device_scratchpad_conf >= ds18b20_device_res) {
ds18b20_device_res = ds18b20_device_scratchpad_conf; ds18b20_device_res = ds18b20_device_scratchpad_conf;
......
...@@ -212,12 +212,15 @@ static void enduser_setup_connected_callback() ...@@ -212,12 +212,15 @@ static void enduser_setup_connected_callback()
} }
} }
#include "pm/swtimer.h"
static void enduser_setup_check_station_start(void) static void enduser_setup_check_station_start(void)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start"); ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start");
os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL); os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL);
SWTIMER_REG_CB(enduser_setup_check_station, SWTIMER_RESUME);
//The function enduser_setup_check_station checks for a successful connection to the configured AP
//My guess: I'm not sure about whether or not user feedback is given via the web interface, but I don't see a problem with letting this timer resume.
os_timer_arm(&(state->check_station_timer), 3*1000, TRUE); os_timer_arm(&(state->check_station_timer), 3*1000, TRUE);
} }
...@@ -317,6 +320,9 @@ static void enduser_setup_check_station(void *p) ...@@ -317,6 +320,9 @@ static void enduser_setup_check_station(void *p)
if (!manual) if (!manual)
{ {
os_timer_setfn(&(state->shutdown_timer), enduser_setup_stop_callback, NULL); os_timer_setfn(&(state->shutdown_timer), enduser_setup_stop_callback, NULL);
SWTIMER_REG_CB(enduser_setup_stop_callback, SWTIMER_RESUME);
//The function enduser_setup_stop_callback frees services and resources used by enduser setup.
//My guess: Since it would lead to a memory leak, it's probably best to resume this timer.
os_timer_arm(&(state->shutdown_timer), 10*1000, FALSE); os_timer_arm(&(state->shutdown_timer), 10*1000, FALSE);
} }
} }
......
...@@ -432,7 +432,8 @@ static int file_g_read( lua_State* L, int n, int16_t end_char, int fd ) ...@@ -432,7 +432,8 @@ static int file_g_read( lua_State* L, int n, int16_t end_char, int fd )
luaM_free(L, heap_mem); luaM_free(L, heap_mem);
heap_mem = NULL; heap_mem = NULL;
} }
return 0; lua_pushnil(L);
return 1;
} }
vfs_lseek(fd, -(n - i), VFS_SEEK_CUR); vfs_lseek(fd, -(n - i), VFS_SEEK_CUR);
......
...@@ -981,6 +981,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -981,6 +981,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
return espconn_status; return espconn_status;
} }
#include "pm/swtimer.h"
// Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client), function(client, connect_return_code) ) // Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client), function(client, connect_return_code) )
static int mqtt_socket_connect( lua_State* L ) static int mqtt_socket_connect( lua_State* L )
{ {
...@@ -1114,6 +1115,9 @@ static int mqtt_socket_connect( lua_State* L ) ...@@ -1114,6 +1115,9 @@ static int mqtt_socket_connect( lua_State* L )
os_timer_disarm(&mud->mqttTimer); os_timer_disarm(&mud->mqttTimer);
os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud);
SWTIMER_REG_CB(mqtt_socket_timer, SWTIMER_RESUME);
//I assume that mqtt_socket_timer connects to the mqtt server, but I'm not really sure what impact light_sleep will have on it.
//My guess: If in doubt, resume the timer
// timer started in socket_connect() // timer started in socket_connect()
if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0))
......
...@@ -38,10 +38,15 @@ static int node_restart( lua_State* L ) ...@@ -38,10 +38,15 @@ static int node_restart( lua_State* L )
return 0; return 0;
} }
static int dsleepMax( lua_State *L ) {
lua_pushnumber(L, (uint64_t)system_rtc_clock_cali_proc()*(0x80000000-1)/(0x1000));
return 1;
}
// Lua: dsleep( us, option ) // Lua: dsleep( us, option )
static int node_deepsleep( lua_State* L ) static int node_deepsleep( lua_State* L )
{ {
uint32 us; uint64 us;
uint8 option; uint8 option;
//us = luaL_checkinteger( L, 1 ); //us = luaL_checkinteger( L, 1 );
// Set deleep option, skip if nil // Set deleep option, skip if nil
...@@ -76,7 +81,7 @@ static int node_deepsleep( lua_State* L ) ...@@ -76,7 +81,7 @@ static int node_deepsleep( lua_State* L )
#ifdef PMSLEEP_ENABLE #ifdef PMSLEEP_ENABLE
#include "pmSleep.h" #include "pm/pmSleep.h"
int node_sleep_resume_cb_ref= LUA_NOREF; int node_sleep_resume_cb_ref= LUA_NOREF;
void node_sleep_resume_cb(void) void node_sleep_resume_cb(void)
...@@ -89,6 +94,7 @@ void node_sleep_resume_cb(void) ...@@ -89,6 +94,7 @@ void node_sleep_resume_cb(void)
// Lua: node.sleep(table) // Lua: node.sleep(table)
static int node_sleep( lua_State* L ) static int node_sleep( lua_State* L )
{ {
#ifdef TIMER_SUSPEND_ENABLE
pmSleep_INIT_CFG(cfg); pmSleep_INIT_CFG(cfg);
cfg.sleep_mode=LIGHT_SLEEP_T; cfg.sleep_mode=LIGHT_SLEEP_T;
...@@ -101,10 +107,19 @@ static int node_sleep( lua_State* L ) ...@@ -101,10 +107,19 @@ static int node_sleep( lua_State* L )
cfg.resume_cb_ptr = &node_sleep_resume_cb; cfg.resume_cb_ptr = &node_sleep_resume_cb;
pmSleep_suspend(&cfg); pmSleep_suspend(&cfg);
#else
dbg_printf("\n The option \"TIMER_SUSPEND_ENABLE\" in \"app/include/user_config.h\" was disabled during FW build!\n");
return luaL_error(L, "node.sleep() is unavailable");
#endif
return 0; return 0;
} }
#else
static int node_sleep( lua_State* L )
{
dbg_printf("\n The options \"TIMER_SUSPEND_ENABLE\" and \"PMSLEEP_ENABLE\" in \"app/include/user_config.h\" were disabled during FW build!\n");
return luaL_error(L, "node.sleep() is unavailable");
}
#endif //PMSLEEP_ENABLE #endif //PMSLEEP_ENABLE
static int node_info( lua_State* L ) static int node_info( lua_State* L )
{ {
lua_pushinteger(L, NODE_VERSION_MAJOR); lua_pushinteger(L, NODE_VERSION_MAJOR);
...@@ -371,6 +386,13 @@ static int node_setcpufreq(lua_State* L) ...@@ -371,6 +386,13 @@ static int node_setcpufreq(lua_State* L)
return 1; return 1;
} }
// Lua: freq = node.getcpufreq()
static int node_getcpufreq(lua_State* L)
{
lua_pushinteger(L, system_get_cpu_freq());
return 1;
}
// Lua: code, reason [, exccause, epc1, epc2, epc3, excvaddr, depc ] = bootreason() // Lua: code, reason [, exccause, epc1, epc2, epc3, excvaddr, depc ] = bootreason()
static int node_bootreason (lua_State *L) static int node_bootreason (lua_State *L)
{ {
...@@ -462,14 +484,23 @@ static int node_stripdebug (lua_State *L) { ...@@ -462,14 +484,23 @@ static int node_stripdebug (lua_State *L) {
// See legc.h and lecg.c. // See legc.h and lecg.c.
static int node_egc_setmode(lua_State* L) { static int node_egc_setmode(lua_State* L) {
unsigned mode = luaL_checkinteger(L, 1); unsigned mode = luaL_checkinteger(L, 1);
unsigned limit = luaL_optinteger (L, 2, 0); int limit = luaL_optinteger (L, 2, 0);
luaL_argcheck(L, mode <= (EGC_ON_ALLOC_FAILURE | EGC_ON_MEM_LIMIT | EGC_ALWAYS), 1, "invalid mode"); luaL_argcheck(L, mode <= (EGC_ON_ALLOC_FAILURE | EGC_ON_MEM_LIMIT | EGC_ALWAYS), 1, "invalid mode");
luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit>0, 1, "limit must be non-zero"); luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit!=0, 1, "limit must be non-zero");
legc_set_mode( L, mode, limit ); legc_set_mode( L, mode, limit );
return 0; return 0;
} }
// totalallocated, estimatedused = node.egc.meminfo()
static int node_egc_meminfo(lua_State *L) {
global_State *g = G(L);
lua_pushinteger(L, g->totalbytes);
lua_pushinteger(L, g->estimate);
return 2;
}
// //
// Lua: osprint(true/false) // Lua: osprint(true/false)
// Allows you to turn on the native Espressif SDK printing // Allows you to turn on the native Espressif SDK printing
...@@ -560,6 +591,7 @@ static int node_random (lua_State *L) { ...@@ -560,6 +591,7 @@ static int node_random (lua_State *L) {
// Module function map // Module function map
static const LUA_REG_TYPE node_egc_map[] = { static const LUA_REG_TYPE node_egc_map[] = {
{ LSTRKEY( "meminfo" ), LFUNCVAL( node_egc_meminfo ) },
{ LSTRKEY( "setmode" ), LFUNCVAL( node_egc_setmode ) }, { LSTRKEY( "setmode" ), LFUNCVAL( node_egc_setmode ) },
{ LSTRKEY( "NOT_ACTIVE" ), LNUMVAL( EGC_NOT_ACTIVE ) }, { LSTRKEY( "NOT_ACTIVE" ), LNUMVAL( EGC_NOT_ACTIVE ) },
{ LSTRKEY( "ON_ALLOC_FAILURE" ), LNUMVAL( EGC_ON_ALLOC_FAILURE ) }, { LSTRKEY( "ON_ALLOC_FAILURE" ), LNUMVAL( EGC_ON_ALLOC_FAILURE ) },
...@@ -577,10 +609,11 @@ static const LUA_REG_TYPE node_task_map[] = { ...@@ -577,10 +609,11 @@ static const LUA_REG_TYPE node_task_map[] = {
static const LUA_REG_TYPE node_map[] = 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( "dsleepMax" ), LFUNCVAL( dsleepMax ) },
{ LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) }, { LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) },
#ifdef PMSLEEP_ENABLE
PMSLEEP_INT_MAP, PMSLEEP_INT_MAP,
#endif #endif
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) }, { LSTRKEY( "info" ), LFUNCVAL( node_info ) },
...@@ -596,6 +629,7 @@ static const LUA_REG_TYPE node_map[] = ...@@ -596,6 +629,7 @@ static const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) }, { LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) },
{ LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) }, { LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) },
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) }, { LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
{ LSTRKEY( "getcpufreq" ), LFUNCVAL( node_getcpufreq) },
{ LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) }, { LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) },
{ LSTRKEY( "restore" ), LFUNCVAL( node_restore) }, { LSTRKEY( "restore" ), LFUNCVAL( node_restore) },
{ LSTRKEY( "random" ), LFUNCVAL( node_random) }, { LSTRKEY( "random" ), LFUNCVAL( node_random) },
......
...@@ -129,6 +129,8 @@ int platform_rotary_exists( unsigned int id ) ...@@ -129,6 +129,8 @@ int platform_rotary_exists( unsigned int id )
return (id < ROTARY_CHANNEL_COUNT); return (id < ROTARY_CHANNEL_COUNT);
} }
#include "pm/swtimer.h"
// Lua: setup(id, phase_a, phase_b [, press]) // Lua: setup(id, phase_a, phase_b [, press])
static int lrotary_setup( lua_State* L ) static int lrotary_setup( lua_State* L )
{ {
...@@ -152,7 +154,14 @@ static int lrotary_setup( lua_State* L ) ...@@ -152,7 +154,14 @@ static int lrotary_setup( lua_State* L )
DATA *d = data[id]; DATA *d = data[id];
memset(d, 0, sizeof(*d)); memset(d, 0, sizeof(*d));
d->id = id;
os_timer_setfn(&d->timer, lrotary_timer_done, (void *) d); os_timer_setfn(&d->timer, lrotary_timer_done, (void *) d);
SWTIMER_REG_CB(lrotary_timer_done, SWTIMER_RESUME);
//lrotary_timer_done checks time elapsed since last event
//My guess: Since proper functionality relies on some variables to be reset via timer callback and state would be invalid anyway.
//It is probably best to resume this timer so it can reset it's state variables
int i; int i;
for (i = 0; i < CALLBACK_COUNT; i++) { for (i = 0; i < CALLBACK_COUNT; i++) {
......
...@@ -319,6 +319,7 @@ static void sntp_handle_result(lua_State *L) { ...@@ -319,6 +319,7 @@ static void sntp_handle_result(lua_State *L) {
} }
} }
#include "pm/swtimer.h"
static void sntp_dosend () static void sntp_dosend ()
{ {
...@@ -326,6 +327,9 @@ static void sntp_dosend () ...@@ -326,6 +327,9 @@ static void sntp_dosend ()
if (state->server_pos < 0) { if (state->server_pos < 0) {
os_timer_disarm(&state->timer); os_timer_disarm(&state->timer);
os_timer_setfn(&state->timer, on_timeout, NULL); os_timer_setfn(&state->timer, on_timeout, NULL);
SWTIMER_REG_CB(on_timeout, SWTIMER_RESUME);
//The function on_timeout calls this function(sntp_dosend) again to handle time sync timeout.
//My guess: Since the WiFi connection is restored after waking from light sleep, it would be possible to contact the SNTP server, So why not let it
state->server_pos = 0; state->server_pos = 0;
} else { } else {
++state->server_pos; ++state->server_pos;
...@@ -708,6 +712,9 @@ static char *set_repeat_mode(lua_State *L, bool enable) ...@@ -708,6 +712,9 @@ static char *set_repeat_mode(lua_State *L, bool enable)
lua_rawgeti(L, LUA_REGISTRYINDEX, state->list_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, state->list_ref);
repeat->list_ref = luaL_ref(L, LUA_REGISTRYINDEX); repeat->list_ref = luaL_ref(L, LUA_REGISTRYINDEX);
os_timer_setfn(&repeat->timer, on_long_timeout, NULL); os_timer_setfn(&repeat->timer, on_long_timeout, NULL);
SWTIMER_REG_CB(on_long_timeout, SWTIMER_RESUME);
//The function on_long_timeout returns errors to the developer
//My guess: Error reporting is a good thing, resume the timer.
os_timer_arm(&repeat->timer, 1000 * 1000, 1); os_timer_arm(&repeat->timer, 1000 * 1000, 1);
} else { } else {
if (repeat) { if (repeat) {
......
...@@ -53,7 +53,7 @@ tmr.softwd(int) ...@@ -53,7 +53,7 @@ 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" #include "pm/swtimer.h"
#define TIMER_MODE_OFF 3 #define TIMER_MODE_OFF 3
#define TIMER_MODE_SINGLE 0 #define TIMER_MODE_SINGLE 0
...@@ -231,68 +231,23 @@ static int tmr_stop(lua_State* L){ ...@@ -231,68 +231,23 @@ static int tmr_stop(lua_State* L){
return 1; return 1;
} }
#ifdef ENABLE_TIMER_SUSPEND #ifdef TIMER_SUSPEND_ENABLE
#define TMR_SUSPEND_REMOVED_MSG "This feature has been removed, we apologize for any inconvenience this may have caused."
static int tmr_suspend(lua_State* L){ static int tmr_suspend(lua_State* L){
timer_t tmr = tmr_get(L, 1); return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
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){ static int tmr_resume(lua_State* L){
timer_t tmr = tmr_get(L, 1); return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
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) static int tmr_suspend_all (lua_State *L){
{ return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
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) static int tmr_resume_all (lua_State *L){
{ return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
sint32 retval = swtmr_resume(NULL);
if(retval!=SWTMR_OK){
return luaL_error(L, swtmr_errorcode2str(retval));
}
else{
lua_pushboolean(L, true);
}
return 1;
} }
...@@ -343,12 +298,7 @@ static int tmr_state(lua_State* L){ ...@@ -343,12 +298,7 @@ static int tmr_state(lua_State* L){
lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0); lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG)); lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG));
#ifdef ENABLE_TIMER_SUSPEND return 2;
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
...@@ -454,7 +404,7 @@ static const LUA_REG_TYPE tmr_dyn_map[] = { ...@@ -454,7 +404,7 @@ 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 #ifdef TIMER_SUSPEND_ENABLE
{ LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
{ LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
#endif #endif
...@@ -463,15 +413,6 @@ static const LUA_REG_TYPE tmr_dyn_map[] = { ...@@ -463,15 +413,6 @@ static const LUA_REG_TYPE tmr_dyn_map[] = {
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG)
static const LUA_REG_TYPE tmr_dbg_map[] = {
{ LSTRKEY( "printRegistry" ), LFUNCVAL( tmr_printRegistry ) },
{ LSTRKEY( "printSuspended" ), LFUNCVAL( tmr_printSuspended ) },
{ LSTRKEY( "printTimerlist" ), LFUNCVAL( tmr_printTimerlist ) },
{ LNILKEY, LNILVAL }
};
#endif
static const LUA_REG_TYPE tmr_map[] = { 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 ) },
...@@ -482,7 +423,7 @@ static const LUA_REG_TYPE tmr_map[] = { ...@@ -482,7 +423,7 @@ static const LUA_REG_TYPE tmr_map[] = {
{ 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 #ifdef TIMER_SUSPEND_ENABLE
{ LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) }, { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
{ LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) }, { LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) },
{ LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) }, { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
...@@ -492,15 +433,13 @@ static const LUA_REG_TYPE tmr_map[] = { ...@@ -492,15 +433,13 @@ static const LUA_REG_TYPE tmr_map[] = {
{ 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(ENABLE_TIMER_SUSPEND) && 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 ) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
#include "pm/swtimer.h"
int luaopen_tmr( lua_State *L ){ int luaopen_tmr( lua_State *L ){
int i; int i;
...@@ -510,16 +449,23 @@ int luaopen_tmr( lua_State *L ){ ...@@ -510,16 +449,23 @@ 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. os_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. os_timer_disarm(&rtc_timer);
ets_timer_disarm(&rtc_timer);
os_timer_setfn(&rtc_timer, rtc_callback, NULL); os_timer_setfn(&rtc_timer, rtc_callback, NULL);
os_timer_arm(&rtc_timer, 1000, 1); os_timer_arm(&rtc_timer, 1000, 1);
SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME);
//The function rtc_callback calls the a function that calibrates the SoftRTC for drift in the esp8266's clock.
//My guess: after the duration of light_sleep there's bound to be some drift in the clock, so a calibration is due.
SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME);
//The function alarm_timer_common handles timers created by the developer via tmr.create().
//No reason not to resume the timers, so resume em'.
return 0; return 0;
} }
......
...@@ -429,7 +429,7 @@ static int wifi_setmaxtxpower( lua_State* L ) ...@@ -429,7 +429,7 @@ static int wifi_setmaxtxpower( lua_State* L )
#ifdef PMSLEEP_ENABLE #ifdef PMSLEEP_ENABLE
/* Begin WiFi suspend functions*/ /* Begin WiFi suspend functions*/
#include "pmSleep.h" #include <pm/pmSleep.h>
static int wifi_resume_cb_ref = LUA_NOREF; // Holds resume callback reference static int wifi_resume_cb_ref = LUA_NOREF; // Holds resume callback reference
static int wifi_suspend_cb_ref = LUA_NOREF; // Holds suspend callback reference static int wifi_suspend_cb_ref = LUA_NOREF; // Holds suspend callback reference
...@@ -511,6 +511,19 @@ static int wifi_resume(lua_State* L) ...@@ -511,6 +511,19 @@ static int wifi_resume(lua_State* L)
} }
/* End WiFi suspend functions*/ /* End WiFi suspend functions*/
#else
static char *susp_note_str = "\n The option \"PMSLEEP_ENABLE\" in \"app/include/user_config.h\" was disabled during FW build!\n";
static char *susp_unavailable_str = "wifi.suspend is unavailable";
static int wifi_suspend(lua_State* L){
dbg_printf("%s", susp_note_str);
return luaL_error(L, susp_unavailable_str);
}
static int wifi_resume(lua_State* L){
dbg_printf("%s", susp_note_str);
return luaL_error(L, susp_unavailable_str);
}
#endif #endif
// Lua: wifi.nullmodesleep() // Lua: wifi.nullmodesleep()
...@@ -963,7 +976,7 @@ static int wifi_station_config( lua_State* L ) ...@@ -963,7 +976,7 @@ static int wifi_station_config( lua_State* L )
lua_State* L_temp = NULL; lua_State* L_temp = NULL;
lua_getfield(L, 1, "connected_cb"); lua_getfield(L, 1, "connect_cb");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
if (lua_isfunction(L, -1)) if (lua_isfunction(L, -1))
...@@ -976,12 +989,12 @@ static int wifi_station_config( lua_State* L ) ...@@ -976,12 +989,12 @@ static int wifi_station_config( lua_State* L )
} }
else else
{ {
return luaL_argerror(L, 1, "connected_cb:not function"); return luaL_argerror(L, 1, "connect_cb:not function");
} }
} }
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "disconnected_cb"); lua_getfield(L, 1, "disconnect_cb");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
if (lua_isfunction(L, -1)) if (lua_isfunction(L, -1))
...@@ -994,7 +1007,7 @@ static int wifi_station_config( lua_State* L ) ...@@ -994,7 +1007,7 @@ static int wifi_station_config( lua_State* L )
} }
else else
{ {
return luaL_argerror(L, 1, "disconnected_cb:not function"); return luaL_argerror(L, 1, "disconnect_cb:not function");
} }
} }
lua_pop(L, 1); lua_pop(L, 1);
...@@ -1145,8 +1158,9 @@ static int wifi_station_listap( lua_State* L ) ...@@ -1145,8 +1158,9 @@ static int wifi_station_listap( lua_State* L )
{ {
return luaL_error( L, "Can't list ap in SOFTAP mode" ); return luaL_error( L, "Can't list ap in SOFTAP mode" );
} }
struct scan_config scan_cfg; // set safe defaults for scan time, all other members are initialized with 0
memset(&scan_cfg, 0, sizeof(scan_cfg)); // source: https://github.com/espressif/ESP8266_NONOS_SDK/issues/103
struct scan_config scan_cfg = {.scan_time = {.passive=120, .active = {.max=120, .min=60}}};
getap_output_format=0; getap_output_format=0;
...@@ -1774,7 +1788,7 @@ static int wifi_ap_listclient( lua_State* L ) ...@@ -1774,7 +1788,7 @@ static int wifi_ap_listclient( lua_State* L )
{ {
if (wifi_get_opmode() == STATION_MODE) if (wifi_get_opmode() == STATION_MODE)
{ {
return luaL_error( L, "Can't list client in STATION_MODE mode" ); return luaL_error( L, "Can't list clients in STATION mode" );
} }
char temp[64]; char temp[64];
...@@ -1787,10 +1801,9 @@ static int wifi_ap_listclient( lua_State* L ) ...@@ -1787,10 +1801,9 @@ static int wifi_ap_listclient( lua_State* L )
{ {
c_sprintf(temp, MACSTR, MAC2STR(station->bssid)); c_sprintf(temp, MACSTR, MAC2STR(station->bssid));
wifi_add_sprintf_field(L, temp, IPSTR, IP2STR(&station->ip)); wifi_add_sprintf_field(L, temp, IPSTR, IP2STR(&station->ip));
next_station = STAILQ_NEXT(station, next); station = STAILQ_NEXT(station, next);
c_free(station);
station = next_station;
} }
wifi_softap_free_station_info();
return 1; return 1;
} }
...@@ -1910,10 +1923,8 @@ static const LUA_REG_TYPE wifi_map[] = { ...@@ -1910,10 +1923,8 @@ static const LUA_REG_TYPE wifi_map[] = {
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) }, { LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
{ LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) }, { LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) },
{ LSTRKEY( "setmaxtxpower" ), LFUNCVAL( wifi_setmaxtxpower ) }, { LSTRKEY( "setmaxtxpower" ), LFUNCVAL( wifi_setmaxtxpower ) },
#ifdef PMSLEEP_ENABLE
{ LSTRKEY( "suspend" ), LFUNCVAL( wifi_suspend ) }, { LSTRKEY( "suspend" ), LFUNCVAL( wifi_suspend ) },
{ LSTRKEY( "resume" ), LFUNCVAL( wifi_resume ) }, { 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 ) },
......
...@@ -19,21 +19,17 @@ ...@@ -19,21 +19,17 @@
void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...); void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...);
void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer); void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer);
static inline void register_lua_cb(lua_State* L,int* cb_ref) static inline void register_lua_cb(lua_State* L,int* cb_ref){
{
int ref=luaL_ref(L, LUA_REGISTRYINDEX); int ref=luaL_ref(L, LUA_REGISTRYINDEX);
if( *cb_ref != LUA_NOREF) if( *cb_ref != LUA_NOREF){
{ luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
} }
*cb_ref = ref; *cb_ref = ref;
} }
static inline void unregister_lua_cb(lua_State* L, int* cb_ref) static inline void unregister_lua_cb(lua_State* L, int* cb_ref){
{ if(*cb_ref != LUA_NOREF){
if(*cb_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
{
luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
*cb_ref = LUA_NOREF; *cb_ref = LUA_NOREF;
} }
} }
...@@ -47,13 +43,13 @@ void wifi_change_default_host_name(void); ...@@ -47,13 +43,13 @@ void wifi_change_default_host_name(void);
#endif #endif
#if defined(EVENT_DEBUG) || defined(NODE_DEBUG) #if defined(EVENT_DEBUG) || defined(NODE_DEBUG)
#define EVENT_DBG(...) c_printf(__VA_ARGS__) #define EVENT_DBG(fmt, ...) c_printf("\n EVENT_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__)
#else #else
#define EVENT_DBG(...) //c_printf(__VA_ARGS__) #define EVENT_DBG(...) //c_printf(__VA_ARGS__)
#endif #endif
enum wifi_suspension_state enum wifi_suspension_state{
{
WIFI_AWAKE = 0, WIFI_AWAKE = 0,
WIFI_SUSPENSION_PENDING = 1, WIFI_SUSPENSION_PENDING = 1,
WIFI_SUSPENDED = 2 WIFI_SUSPENDED = 2
......
...@@ -22,13 +22,6 @@ ...@@ -22,13 +22,6 @@
//variables for wifi event monitor //variables for wifi event monitor
static task_handle_t wifi_event_monitor_task_id; //variable to hold task id for task handler(process_event_queue) static task_handle_t wifi_event_monitor_task_id; //variable to hold task id for task handler(process_event_queue)
typedef struct evt_queue{
System_Event_t *evt;
struct evt_queue * next;
}evt_queue_t; //structure to hold pointers to event info and next item in queue
static evt_queue_t *wifi_event_queue_head; //pointer to beginning of queue
static evt_queue_t *wifi_event_queue_tail; //pointer to end of queue
static int wifi_event_cb_ref[EVENT_MAX+1] = { [0 ... EVENT_MAX] = LUA_NOREF}; //holds references to registered Lua callbacks static int wifi_event_cb_ref[EVENT_MAX+1] = { [0 ... EVENT_MAX] = LUA_NOREF}; //holds references to registered Lua callbacks
#ifdef LUA_USE_MODULES_WIFI_MONITOR #ifdef LUA_USE_MODULES_WIFI_MONITOR
...@@ -62,9 +55,11 @@ int wifi_event_monitor_register(lua_State* L) ...@@ -62,9 +55,11 @@ int wifi_event_monitor_register(lua_State* L)
} }
} }
static sint32_t event_queue_ref = LUA_NOREF;
static void wifi_event_monitor_handle_event_cb(System_Event_t *evt) static void wifi_event_monitor_handle_event_cb(System_Event_t *evt)
{ {
EVENT_DBG("\n\twifi_event_monitor_handle_event_cb is called\n"); EVENT_DBG("was called (Event:%d)", evt->event);
#ifdef LUA_USE_MODULES_WIFI_MONITOR #ifdef LUA_USE_MODULES_WIFI_MONITOR
if (hook_fn && hook_fn(evt)) { if (hook_fn && hook_fn(evt)) {
...@@ -79,38 +74,66 @@ static void wifi_event_monitor_handle_event_cb(System_Event_t *evt) ...@@ -79,38 +74,66 @@ static void wifi_event_monitor_handle_event_cb(System_Event_t *evt)
evt->event == EVENT_SOFTAPMODE_STADISCONNECTED || evt->event == EVENT_SOFTAPMODE_PROBEREQRECVED || evt->event == EVENT_SOFTAPMODE_STADISCONNECTED || evt->event == EVENT_SOFTAPMODE_PROBEREQRECVED ||
evt->event == EVENT_OPMODE_CHANGED))) evt->event == EVENT_OPMODE_CHANGED)))
{ {
evt_queue_t *temp = (evt_queue_t*)c_malloc(sizeof(evt_queue_t)); //allocate memory for new queue item lua_State* L = lua_getstate();
temp->evt = (System_Event_t*)c_malloc(sizeof(System_Event_t)); //allocate memory to hold event structure if(event_queue_ref == LUA_NOREF){ //if event queue has not been created, create it now
if(!temp || !temp->evt) lua_newtable(L);
{ event_queue_ref = luaL_ref(L, LUA_REGISTRYINDEX);
luaL_error(lua_getstate(), "wifi.eventmon malloc: out of memory");
return;
} }
c_memcpy(temp->evt, evt, sizeof(System_Event_t)); //copy event data to new struct lua_rawgeti(L, LUA_REGISTRYINDEX, event_queue_ref);
if(wifi_event_queue_head == NULL && wifi_event_queue_tail == NULL)// if queue is empty add item to queue System_Event_t* evt_tmp = lua_newuserdata(L, sizeof(System_Event_t));
{ c_memcpy(evt_tmp, evt, sizeof(System_Event_t)); //copy event data to new struct
wifi_event_queue_head = wifi_event_queue_tail = temp; sint32_t evt_ud_ref = luaL_ref(L, LUA_REGISTRYINDEX);
EVENT_DBG("\n\tqueue empty, adding event and posting task\n"); size_t queue_len = lua_objlen(L, -1);
//add event to queue
lua_pushnumber(L, queue_len+1);
lua_pushnumber(L, evt_ud_ref);
lua_rawset(L, -3);
if(queue_len == 0){ //if queue was empty, post task
EVENT_DBG("Posting task");
task_post_low(wifi_event_monitor_task_id, false); task_post_low(wifi_event_monitor_task_id, false);
} }
else //if queue is not empty append item to end of queue else{
{ EVENT_DBG("Appending queue, items in queue: %d", lua_objlen(L, -1));
wifi_event_queue_tail->next=temp;
wifi_event_queue_tail=temp;
EVENT_DBG("\n\tqueue not empty, appending queue\n");
} }
} lua_pop(L, 1);
} //else{} //there are no callbacks registered, so the event can't be processed
} }
static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 priority) static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 priority)
{ {
lua_State* L = lua_getstate(); lua_State* L = lua_getstate();
evt_queue_t *temp = wifi_event_queue_head; //copy event_queue_head pointer to temporary pointer lua_rawgeti(L, LUA_REGISTRYINDEX, event_queue_ref);
System_Event_t *evt = temp->evt; //copy event data pointer to temporary pointer int index = 1;
lua_rawgeti(L, 1, index);
sint32 event_ref = lua_tonumber(L, -1);
lua_pop(L, 1);
//remove event reference from queue
int queue_length = lua_objlen(L, 1);
lua_rawgeti(L, 1, index);
for(; index<queue_length;index++){
lua_rawgeti(L, 1, index+1);
lua_rawseti(L, 1, index);
}
lua_pushnil(L);
lua_rawseti(L, 1, queue_length);
lua_pop(L, 1);
lua_rawgeti(L, LUA_REGISTRYINDEX, event_ref); //get event userdata from registry
System_Event_t *evt = lua_touserdata(L, -1);
EVENT_DBG("\t\tevent %u\n", evt->event); lua_pop(L, 1); //pop userdata from stack
queue_length = lua_objlen(L, 1);
if (queue_length>0){
task_post_low(wifi_event_monitor_task_id, false); //post task to process next item in queue
EVENT_DBG("%d events left in queue, posting task", queue_length);
}
lua_pop(L, 1); //pop event queue from stack
if(wifi_event_cb_ref[evt->event] != LUA_NOREF) // check if user has registered a callback if(wifi_event_cb_ref[evt->event] != LUA_NOREF) // check if user has registered a callback
{ {
...@@ -130,107 +153,97 @@ static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 pri ...@@ -130,107 +153,97 @@ static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 pri
switch (evt->event) switch (evt->event)
{ {
case EVENT_STAMODE_CONNECTED: case EVENT_STAMODE_CONNECTED:
EVENT_DBG("\n\tSTAMODE_CONNECTED\n"); EVENT_DBG("Event: %d (STAMODE_CONNECTED)", EVENT_STAMODE_CONNECTED);
wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.connected.ssid); wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.connected.ssid);
wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.connected.bssid)); wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.connected.bssid));
wifi_add_int_field(L, "channel", evt->event_info.connected.channel); wifi_add_int_field(L, "channel", evt->event_info.connected.channel);
EVENT_DBG("\tConnected to SSID %s, Channel %d\n", EVENT_DBG("Connected to SSID %s, Channel %d",
evt->event_info.connected.ssid, evt->event_info.connected.ssid,
evt->event_info.connected.channel); evt->event_info.connected.channel);
break; break;
case EVENT_STAMODE_DISCONNECTED: case EVENT_STAMODE_DISCONNECTED:
EVENT_DBG("\n\tSTAMODE_DISCONNECTED\n"); EVENT_DBG("Event: %d (STAMODE_DISCONNECTED)", EVENT_STAMODE_DISCONNECTED);
wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.disconnected.ssid); wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.disconnected.ssid);
wifi_add_int_field(L, "reason", evt->event_info.disconnected.reason); wifi_add_int_field(L, "reason", evt->event_info.disconnected.reason);
wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.disconnected.bssid)); wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.disconnected.bssid));
EVENT_DBG("\tDisconnect from SSID %s, reason %d\n", EVENT_DBG("Disconnect from SSID %s, reason %d",
evt->event_info.disconnected.ssid, evt->event_info.disconnected.ssid,
evt->event_info.disconnected.reason); evt->event_info.disconnected.reason);
break; break;
case EVENT_STAMODE_AUTHMODE_CHANGE: case EVENT_STAMODE_AUTHMODE_CHANGE:
EVENT_DBG("\n\tSTAMODE_AUTHMODE_CHANGE\n"); EVENT_DBG("Event: %d (STAMODE_AUTHMODE_CHANGE)", EVENT_STAMODE_AUTHMODE_CHANGE);
wifi_add_int_field(L, "old_auth_mode", evt->event_info.auth_change.old_mode); wifi_add_int_field(L, "old_auth_mode", evt->event_info.auth_change.old_mode);
wifi_add_int_field(L, "new_auth_mode", evt->event_info.auth_change.new_mode); wifi_add_int_field(L, "new_auth_mode", evt->event_info.auth_change.new_mode);
EVENT_DBG("\tAuthmode: %u -> %u\n", EVENT_DBG("Authmode: %u -> %u",
evt->event_info.auth_change.old_mode, evt->event_info.auth_change.old_mode,
evt->event_info.auth_change.new_mode); evt->event_info.auth_change.new_mode);
break; break;
case EVENT_STAMODE_GOT_IP: case EVENT_STAMODE_GOT_IP:
EVENT_DBG("\n\tGOT_IP\n"); EVENT_DBG("Event: %d (STAMODE_GOT_IP)", EVENT_STAMODE_GOT_IP);
wifi_add_sprintf_field(L, "IP", IPSTR, IP2STR(&evt->event_info.got_ip.ip)); wifi_add_sprintf_field(L, "IP", IPSTR, IP2STR(&evt->event_info.got_ip.ip));
wifi_add_sprintf_field(L, "netmask", IPSTR, IP2STR(&evt->event_info.got_ip.mask)); wifi_add_sprintf_field(L, "netmask", IPSTR, IP2STR(&evt->event_info.got_ip.mask));
wifi_add_sprintf_field(L, "gateway", IPSTR, IP2STR(&evt->event_info.got_ip.gw)); wifi_add_sprintf_field(L, "gateway", IPSTR, IP2STR(&evt->event_info.got_ip.gw));
EVENT_DBG("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n", EVENT_DBG("IP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "",
IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.ip),
IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.mask),
IP2STR(&evt->event_info.got_ip.gw)); IP2STR(&evt->event_info.got_ip.gw));
break; break;
case EVENT_STAMODE_DHCP_TIMEOUT: case EVENT_STAMODE_DHCP_TIMEOUT:
EVENT_DBG("\n\tSTAMODE_DHCP_TIMEOUT\n"); EVENT_DBG("Event: %d (STAMODE_DHCP_TIMEOUT)", EVENT_STAMODE_DHCP_TIMEOUT);
break; break;
case EVENT_SOFTAPMODE_STACONNECTED: case EVENT_SOFTAPMODE_STACONNECTED:
EVENT_DBG("\n\tSOFTAPMODE_STACONNECTED\n"); EVENT_DBG("Event: %d (SOFTAPMODE_STACONNECTED)", EVENT_SOFTAPMODE_STACONNECTED);
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_connected.mac)); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_connected.mac));
wifi_add_int_field(L, "AID", evt->event_info.sta_connected.aid); wifi_add_int_field(L, "AID", evt->event_info.sta_connected.aid);
EVENT_DBG("\tStation: " MACSTR "join, AID = %d\n", EVENT_DBG("Station: " MACSTR "join, AID = %d",
MAC2STR(evt->event_info.sta_connected.mac), MAC2STR(evt->event_info.sta_connected.mac),
evt->event_info.sta_connected.aid); evt->event_info.sta_connected.aid);
break; break;
case EVENT_SOFTAPMODE_STADISCONNECTED: case EVENT_SOFTAPMODE_STADISCONNECTED:
EVENT_DBG("\n\tSOFTAPMODE_STADISCONNECTED\n"); EVENT_DBG("Event: %d (SOFTAPMODE_STADISCONNECTED)", EVENT_SOFTAPMODE_STADISCONNECTED);
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_disconnected.mac)); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_disconnected.mac));
wifi_add_int_field(L, "AID", evt->event_info.sta_disconnected.aid); wifi_add_int_field(L, "AID", evt->event_info.sta_disconnected.aid);
EVENT_DBG("\tstation: " MACSTR "leave, AID = %d\n", EVENT_DBG("station: " MACSTR "leave, AID = %d",
MAC2STR(evt->event_info.sta_disconnected.mac), MAC2STR(evt->event_info.sta_disconnected.mac),
evt->event_info.sta_disconnected.aid); evt->event_info.sta_disconnected.aid);
break; break;
case EVENT_SOFTAPMODE_PROBEREQRECVED: case EVENT_SOFTAPMODE_PROBEREQRECVED:
EVENT_DBG("\n\tSOFTAPMODE_PROBEREQRECVED\n"); EVENT_DBG("Event: %d (SOFTAPMODE_PROBEREQRECVED)", EVENT_SOFTAPMODE_PROBEREQRECVED);
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.ap_probereqrecved.mac)); wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.ap_probereqrecved.mac));
wifi_add_int_field(L, "RSSI", evt->event_info.ap_probereqrecved.rssi); wifi_add_int_field(L, "RSSI", evt->event_info.ap_probereqrecved.rssi);
EVENT_DBG("Station PROBEREQ: " MACSTR " RSSI = %d\n", EVENT_DBG("Station PROBEREQ: " MACSTR " RSSI = %d",
MAC2STR(evt->event_info.ap_probereqrecved.mac), MAC2STR(evt->event_info.ap_probereqrecved.mac),
evt->event_info.ap_probereqrecved.rssi); evt->event_info.ap_probereqrecved.rssi);
break; break;
case EVENT_OPMODE_CHANGED: case EVENT_OPMODE_CHANGED:
EVENT_DBG("\n\tOPMODE_CHANGED\n"); EVENT_DBG("Event: %d (OPMODE_CHANGED)", EVENT_OPMODE_CHANGED);
wifi_add_int_field(L, "old_mode", evt->event_info.opmode_changed.old_opmode); wifi_add_int_field(L, "old_mode", evt->event_info.opmode_changed.old_opmode);
wifi_add_int_field(L, "new_mode", evt->event_info.opmode_changed.new_opmode); wifi_add_int_field(L, "new_mode", evt->event_info.opmode_changed.new_opmode);
EVENT_DBG("\topmode: %u -> %u\n", EVENT_DBG("opmode: %u -> %u",
evt->event_info.opmode_changed.old_opmode, evt->event_info.opmode_changed.old_opmode,
evt->event_info.opmode_changed.new_opmode); evt->event_info.opmode_changed.new_opmode);
break; break;
default://if event is not implemented, return event id default://if event is not implemented, return event id
EVENT_DBG("\n\tswitch/case default\n"); EVENT_DBG("Event: %d (switch/case default)", evt->event);
wifi_add_sprintf_field(L, "info", "event %u not implemented", evt->event); wifi_add_sprintf_field(L, "info", "event %u not implemented", evt->event);
break; break;
} }
lua_call(L, 1, 0); //execute user's callback and pass Lua table
if (wifi_event_queue_head == wifi_event_queue_tail) //if queue is empty.. luaL_unref(L, LUA_REGISTRYINDEX, event_ref); //the userdata containing event info is no longer needed
{ event_ref = LUA_NOREF;
wifi_event_queue_head = wifi_event_queue_tail = NULL; //set queue pointers to NULL
EVENT_DBG("\n\tQueue empty\n");
}
else //if queue is not empty...
{
wifi_event_queue_head = wifi_event_queue_head->next; //append item to end of queue
EVENT_DBG("\n\tmore in queue, posting task...\n");
task_post_low(wifi_event_monitor_task_id, false); //post task to process next item in queue
}
c_free(evt); //free memory used by event structure lua_call(L, 1, 0); //execute user's callback and pass Lua table
c_free(temp); //free memory used by queue structure return;
} }
#ifdef WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE #ifdef WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "user_interface.h" #include "user_interface.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "osapi.h" #include "osapi.h"
#include "swTimer/swTimer.h" #include "pm/swtimer.h"
#include "ws2812.h" #include "ws2812.h"
#include "color_utils.h" #include "color_utils.h"
......
...@@ -1056,6 +1056,7 @@ mdns_dup_info(const struct nodemcu_mdns_info *info) { ...@@ -1056,6 +1056,7 @@ mdns_dup_info(const struct nodemcu_mdns_info *info) {
return result; return result;
} }
#include "pm/swtimer.h"
/** /**
* Initialize the resolver: set up the UDP pcb and configure the default server * Initialize the resolver: set up the UDP pcb and configure the default server
* (NEW IP). * (NEW IP).
...@@ -1130,6 +1131,9 @@ nodemcu_mdns_init(struct nodemcu_mdns_info *info) { ...@@ -1130,6 +1131,9 @@ nodemcu_mdns_init(struct nodemcu_mdns_info *info) {
//MDNS_DBG("About to start timer\n"); //MDNS_DBG("About to start timer\n");
os_timer_disarm(&mdns_timer); os_timer_disarm(&mdns_timer);
os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info); os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
SWTIMER_REG_CB(mdns_reg, SWTIMER_RESUME);
//the function mdns_reg registers the mdns device on the network
//My guess: Since wifi connection is restored after waking from light_sleep, the related timer would have no problem resuming it's normal function.
os_timer_arm(&mdns_timer, 1000 * 280, 1); os_timer_arm(&mdns_timer, 1000 * 280, 1);
/* kick off the first one right away */ /* kick off the first one right away */
mdns_reg_handler_restart(); mdns_reg_handler_restart();
......
#include "pmSleep.h" #include <pm/pmSleep.h>
#ifdef PMSLEEP_ENABLE #ifdef PMSLEEP_ENABLE
#define STRINGIFY_VAL(x) #x #define STRINGIFY_VAL(x) #x
#define STRINGIFY(x) STRINGIFY_VAL(x) #define STRINGIFY(x) STRINGIFY_VAL(x)
//TODO: figure out why timed light_sleep doesn't work
//holds duration error string //holds duration error string
//uint32 PMSLEEP_SLEEP_MAX_TIME=FPM_SLEEP_MAX_TIME-1; //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"; const char *PMSLEEP_DURATION_ERR_STR="duration: 0 or "STRINGIFY(PMSLEEP_SLEEP_MIN_TIME)"-"STRINGIFY(PMSLEEP_SLEEP_MAX_TIME)" us";
...@@ -28,17 +30,18 @@ static void wifi_suspended_timer_cb(int arg); ...@@ -28,17 +30,18 @@ static void wifi_suspended_timer_cb(int arg);
/* INTERNAL FUNCTIONS */ /* INTERNAL FUNCTIONS */
#include "swTimer/swTimer.h"
static void suspend_all_timers(void){ static void suspend_all_timers(void){
#ifdef ENABLE_TIMER_SUSPEND #ifdef TIMER_SUSPEND_ENABLE
swtmr_suspend(NULL); extern void swtmr_suspend_timers();
swtmr_suspend_timers();
#endif #endif
return; return;
} }
static void resume_all_timers(void){ static void resume_all_timers(void){
#ifdef ENABLE_TIMER_SUSPEND #ifdef TIMER_SUSPEND_ENABLE
swtmr_resume(NULL); extern void swtmr_resume_timers();
swtmr_resume_timers();
#endif #endif
return; return;
} }
...@@ -49,7 +52,7 @@ static void null_mode_check_timer_cb(void* arg){ ...@@ -49,7 +52,7 @@ static void null_mode_check_timer_cb(void* arg){
if(current_config.sleep_mode == LIGHT_SLEEP_T){ if(current_config.sleep_mode == LIGHT_SLEEP_T){
if((READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S)) == 0 && 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){ (READ_PERI_REG(UART_STATUS(1)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S)) == 0){
ets_timer_disarm(&null_mode_check_timer); os_timer_disarm(&null_mode_check_timer);
suspend_all_timers(); suspend_all_timers();
//Ensure UART 0/1 TX FIFO is clear //Ensure UART 0/1 TX FIFO is clear
SET_PERI_REG_MASK(UART_CONF0(0), UART_TXFIFO_RST);//RESET FIFO SET_PERI_REG_MASK(UART_CONF0(0), UART_TXFIFO_RST);//RESET FIFO
...@@ -71,6 +74,8 @@ static void null_mode_check_timer_cb(void* arg){ ...@@ -71,6 +74,8 @@ static void null_mode_check_timer_cb(void* arg){
PMSLEEP_DBG("wifi_fpm_do_sleep success, starting wifi_suspend_test timer"); PMSLEEP_DBG("wifi_fpm_do_sleep success, starting wifi_suspend_test timer");
os_timer_disarm(&wifi_suspended_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_setfn(&wifi_suspended_test_timer, (os_timer_func_t*)wifi_suspended_timer_cb, NULL);
//The callback wifi_suspended_timer_cb detects when the esp8266 has successfully entered modem_sleep and executes the developer's suspend_cb.
//Since this timer is only used in modem_sleep and will never be active outside of modem_sleep, it is unnecessary to register the cb with SWTIMER_REG_CB.
os_timer_arm(&wifi_suspended_test_timer, 1, 1); os_timer_arm(&wifi_suspended_test_timer, 1, 1);
} }
else{ // This should never happen. if it does, return the value for error reporting else{ // This should never happen. if it does, return the value for error reporting
...@@ -78,7 +83,7 @@ static void null_mode_check_timer_cb(void* arg){ ...@@ -78,7 +83,7 @@ static void null_mode_check_timer_cb(void* arg){
PMSLEEP_ERR("wifi_fpm_do_sleep returned %d", retval_wifi_fpm_do_sleep); PMSLEEP_ERR("wifi_fpm_do_sleep returned %d", retval_wifi_fpm_do_sleep);
} }
} }
ets_timer_disarm(&null_mode_check_timer); os_timer_disarm(&null_mode_check_timer);
return; return;
} }
} }
...@@ -173,24 +178,24 @@ uint8 pmSleep_get_state(void){ ...@@ -173,24 +178,24 @@ uint8 pmSleep_get_state(void){
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){ 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_Integer Linteger_tmp = 0;
lua_getfield(L, table_idx, "duration"); if( cfg->sleep_mode == MODEM_SLEEP_T ){ //WiFi suspend
if( !lua_isnil(L, -1) ){ /* found? */ lua_getfield(L, table_idx, "duration");
if( lua_isnumber(L, -1) ){ if( !lua_isnil(L, -1) ){ /* found? */
lua_Integer Linteger=luaL_checkinteger(L, -1); if( lua_isnumber(L, -1) ){
luaL_argcheck(L,(((Linteger >= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) || lua_Integer Linteger=luaL_checkinteger(L, -1);
(Linteger == 0)), table_idx, PMSLEEP_DURATION_ERR_STR); luaL_argcheck(L,(((Linteger >= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) ||
cfg->sleep_duration = (uint32)Linteger; // Get suspend duration (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{ else{
return luaL_argerror( L, table_idx, "duration: must be number" ); return luaL_argerror( L, table_idx, PMSLEEP_DURATION_ERR_STR );
} }
} lua_pop(L, 1);
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"); lua_getfield(L, table_idx, "suspend_cb");
if( !lua_isnil(L, -1) ){ /* found? */ if( !lua_isnil(L, -1) ){ /* found? */
if( lua_isfunction(L, -1) ){ if( lua_isfunction(L, -1) ){
...@@ -204,7 +209,7 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, ...@@ -204,7 +209,7 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg,
lua_pop(L, 1); lua_pop(L, 1);
} }
else if (cfg->sleep_mode == LIGHT_SLEEP_T){ //CPU suspend else if (cfg->sleep_mode == LIGHT_SLEEP_T){ //CPU suspend
#ifdef ENABLE_TIMER_SUSPEND #ifdef TIMER_SUSPEND_ENABLE
lua_getfield(L, table_idx, "wake_pin"); lua_getfield(L, table_idx, "wake_pin");
if( !lua_isnil(L, -1) ){ /* found? */ if( !lua_isnil(L, -1) ){ /* found? */
if( lua_isnumber(L, -1) ){ if( lua_isnumber(L, -1) ){
...@@ -216,9 +221,11 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg, ...@@ -216,9 +221,11 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg,
return luaL_argerror( L, table_idx, "wake_pin: must be number" ); return luaL_argerror( L, table_idx, "wake_pin: must be number" );
} }
} }
else if(cfg->sleep_duration == 0){ else{
return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" ); return luaL_argerror( L, table_idx, "wake_pin: must specify pin" );
} // else if(cfg->sleep_duration == 0){
// return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" );
}
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, table_idx, "int_type"); lua_getfield(L, table_idx, "int_type");
...@@ -300,7 +307,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ ...@@ -300,7 +307,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
PMSLEEP_DBG("START"); PMSLEEP_DBG("START");
lua_State* L = lua_getstate(); lua_State* L = lua_getstate();
#ifndef ENABLE_TIMER_SUSPEND #ifndef TIMER_SUSPEND_ENABLE
if(cfg->sleep_mode == LIGHT_SLEEP_T){ if(cfg->sleep_mode == LIGHT_SLEEP_T){
luaL_error(L, "timer suspend API is disabled, light sleep unavailable"); luaL_error(L, "timer suspend API is disabled, light sleep unavailable");
return; return;
...@@ -336,7 +343,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ ...@@ -336,7 +343,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
wifi_fpm_open(); // Enable force sleep API wifi_fpm_open(); // Enable force sleep API
if (cfg->sleep_mode == LIGHT_SLEEP_T){ if (cfg->sleep_mode == LIGHT_SLEEP_T){
#ifdef ENABLE_TIMER_SUSPEND #ifdef TIMER_SUSPEND_ENABLE
if(platform_gpio_exists(cfg->wake_pin) && cfg->wake_pin > 0){ 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); PMSLEEP_DBG("Wake-up pin is %d\t interrupt type is %d", cfg->wake_pin, cfg->int_type);
...@@ -366,10 +373,11 @@ void pmSleep_suspend(pmSleep_param_t *cfg){ ...@@ -366,10 +373,11 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
c_memcpy(&current_config, cfg, sizeof(pmSleep_param_t)); c_memcpy(&current_config, cfg, sizeof(pmSleep_param_t));
PMSLEEP_DBG("sleep duration is %d", current_config.sleep_duration); PMSLEEP_DBG("sleep duration is %d", current_config.sleep_duration);
//this timer intentionally bypasses the swtimer timer registration process os_timer_disarm(&null_mode_check_timer);
ets_timer_disarm(&null_mode_check_timer); os_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false);
ets_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false); //The function null_mode_check_timer_cb checks that the esp8266 has successfully changed the opmode to NULL_MODE prior to entering LIGHT_SLEEP
ets_timer_arm_new(&null_mode_check_timer, 1, 1, 1); //This callback doesn't need to be registered with SWTIMER_REG_CB since the timer will have terminated before entering LIGHT_SLEEP
os_timer_arm(&null_mode_check_timer, 1, 1);
} }
else{ else{
PMSLEEP_ERR("opmode change fail"); PMSLEEP_ERR("opmode change fail");
......
/* swTimer.c SDK timer suspend API
*
* SDK software timer API info:
*
* The SDK software timer uses a linked list called `os_timer_t* timer_list` to keep track of
* all currently armed timers.
*
* The SDK software timer API executes in a task. The priority of this task in relation to the
* application level tasks is unknown (at time of writing).
*
*
* To determine when a timer's callback should be executed, the respective timer's `timer_expire`
* variable is compared to the hardware counter(FRC2), then, if the timer's `timer_expire` is
* less than the current FRC2 count, the timer's callback is fired.
*
* The timers in this list are organized in an ascending order starting with the timer
* with the lowest timer_expire.
*
* When a timer expires that has a timer_period greater than 0, timer_expire is changed to
* current FRC2 + timer_period, then the timer is inserted back in to the list in the correct position.
*
* when using millisecond(default) timers, FRC2 resolution is 312.5 ticks per millisecond.
*
*
* TIMER SUSPEND API INFO:
*
* Timer suspension is achieved by first finding any non-SDK timers by comparing the timer function callback pointer
* of each timer in "timer_list" to a list of registered timer callback pointers stored in the Lua registry.
* If a timer with a corresponding registered callback pointer is found, the timer's timer_expire field is is compared
* to the current FRC2 count and the difference is saved along with the other timer parameters to temporary variables.
* The timer is then disarmed and the parameters are copied back, the timer pointer is then
* added to a separate linked list of which the head pointer is stored as a lightuserdata in the lua registry.
*
* Resuming the timers is achieved by first retrieving the lightuserdata holding the suspended timer list head pointer.
* Then, starting with the beginning of the list the current FRC2 count is added back to the timer's timer_expire, then
* the timer is manually added back to "timer_list" in an ascending order.
* Once there are no more suspended timers, the function returns
*
*
*/#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include "user_modules.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "ctype.h"
#include "c_types.h"
//#define SWTMR_DEBUG
#if !defined(SWTMR_DBG) && defined(LUA_USE_MODULES_SWTMR_DBG)
#define SWTMR_DEBUG
#endif
//this section specifies which lua registry to use. LUA_GLOBALSINDEX or LUA_REGISTRYINDEX
#ifdef SWTMR_DEBUG
#define SWTMR_DBG(fmt, ...) dbg_printf("\n SWTMR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__)
#define L_REGISTRY LUA_GLOBALSINDEX
#define CB_LIST_STR "timer_cb_ptrs"
#define SUSP_LIST_STR "suspended_tmr_LL_head"
#else
#define SWTMR_DBG(...)
#define L_REGISTRY LUA_REGISTRYINDEX
#define CB_LIST_STR "cb"
#define SUSP_LIST_STR "st"
#endif
typedef struct tmr_cb_queue{
os_timer_func_t *tmr_cb_ptr;
uint8 suspend_policy;
struct tmr_cb_queue * next;
}tmr_cb_queue_t;
typedef struct cb_registry_item{
os_timer_func_t *tmr_cb_ptr;
uint8 suspend_policy;
}cb_registry_item_t;
/* Internal variables */
static tmr_cb_queue_t* register_queue = NULL;
static task_handle_t cb_register_task_id = 0; //variable to hold task id for task handler(process_cb_register_queue)
/* Function declarations */
//void swtmr_cb_register(void* timer_cb_ptr, uint8 resume_policy);
static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy);
static void process_cb_register_queue(task_param_t param, uint8 priority);
#ifdef SWTMR_DEBUG
#define push_swtmr_registry_key(L) lua_pushstring(L, "SWTMR_registry_key")
#else
#define push_swtmr_registry_key(L) lua_pushlightuserdata(L, &register_queue);
#endif
#include <pm/swtimer.h>
void swtmr_suspend_timers(){
lua_State* L = lua_getstate();
//get swtimer table
push_swtmr_registry_key(L);
lua_rawget(L, L_REGISTRY);
//get cb_list table
lua_pushstring(L, CB_LIST_STR);
lua_rawget(L, -2);
//check for existence of the swtimer table and the cb_list table, return if not found
if(!lua_istable(L, -2) || !lua_istable(L, -1)){
// not necessarily an error maybe there are legitimately no timers to suspend
lua_pop(L, 2);
return;
}
os_timer_t* suspended_timer_list_head = NULL;
os_timer_t* suspended_timer_list_tail = NULL;
//get suspended_timer_list table
lua_pushstring(L, SUSP_LIST_STR);
lua_rawget(L, -3);
//if suspended_timer_list exists, find tail of list
if(lua_isuserdata(L, -1)){
suspended_timer_list_head = suspended_timer_list_tail = lua_touserdata(L, -1);
while(suspended_timer_list_tail->timer_next != NULL){
suspended_timer_list_tail = suspended_timer_list_tail->timer_next;
}
}
lua_pop(L, 1);
//get length of lua table containing the callback pointers
size_t registered_cb_qty = lua_objlen(L, -1);
//allocate a temporary array to hold the list of callback pointers
cb_registry_item_t** cb_reg_array = c_zalloc(sizeof(cb_registry_item_t*)*registered_cb_qty);
if(!cb_reg_array){
luaL_error(L, "%s: unable to suspend timers, out of memory!", __func__);
return;
}
uint8 index = 0;
//convert lua table cb_list to c array
lua_pushnil(L);
while(lua_next(L, -2) != 0){
if(lua_isuserdata(L, -1)){
cb_reg_array[index] = lua_touserdata(L, -1);
}
lua_pop(L, 1);
index++;
}
//the cb_list table is no longer needed, pop it from the stack
lua_pop(L, 1);
volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
os_timer_t* timer_ptr = timer_list;
uint32 expire_temp = 0;
uint32 period_temp = 0;
void* arg_temp = NULL;
/* In this section, the SDK's timer_list is traversed to find any timers that have a registered callback pointer.
* If a registered callback is found, the timer is suspended by saving the difference
* between frc2_count and timer_expire then the timer is disarmed and placed into suspended_timer_list
* so it can later be resumed.
*/
while(timer_ptr != NULL){
os_timer_t* next_timer = (os_timer_t*)0xffffffff;
for(size_t i = 0; i < registered_cb_qty; i++){
if(timer_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){
//current timer will be suspended, next timer's pointer will be needed to continue processing timer_list
next_timer = timer_ptr->timer_next;
//store timer parameters temporarily so the timer can be disarmed
if(timer_ptr->timer_expire < frc2_count)
expire_temp = 2; // 16 us in ticks (1 tick = ~3.2 us) (arbitrarily chosen value)
else
expire_temp = timer_ptr->timer_expire - frc2_count;
period_temp = timer_ptr->timer_period;
arg_temp = timer_ptr->timer_arg;
if(timer_ptr->timer_period == 0 && cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){
SWTMR_DBG("Warning: suspend_policy(RESTART) is not compatible with single-shot timer(%p), changing suspend_policy to (RESUME)", timer_ptr);
cb_reg_array[i]->suspend_policy = SWTIMER_RESUME;
}
//remove the timer from timer_list so we don't have to.
os_timer_disarm(timer_ptr);
timer_ptr->timer_next = NULL;
//this section determines timer behavior on resume
if(cb_reg_array[i]->suspend_policy == SWTIMER_DROP){
SWTMR_DBG("timer(%p) was disarmed and will not be resumed", timer_ptr);
}
else if(cb_reg_array[i]->suspend_policy == SWTIMER_IMMEDIATE){
timer_ptr->timer_expire = 1;
SWTMR_DBG("timer(%p) will fire immediately on resume", timer_ptr);
}
else if(cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){
timer_ptr->timer_expire = period_temp;
SWTMR_DBG("timer(%p) will be restarted on resume", timer_ptr);
}
else{
timer_ptr->timer_expire = expire_temp;
SWTMR_DBG("timer(%p) will be resumed with remaining time", timer_ptr);
}
if(cb_reg_array[i]->suspend_policy != SWTIMER_DROP){
timer_ptr->timer_period = period_temp;
timer_ptr->timer_func = cb_reg_array[i]->tmr_cb_ptr;
timer_ptr->timer_arg = arg_temp;
//add timer to suspended_timer_list
if(suspended_timer_list_head == NULL){
suspended_timer_list_head = timer_ptr;
suspended_timer_list_tail = timer_ptr;
}
else{
suspended_timer_list_tail->timer_next = timer_ptr;
suspended_timer_list_tail = timer_ptr;
}
}
}
}
//if timer was suspended, timer_ptr->timer_next is invalid, use next_timer instead.
if(next_timer != (os_timer_t*)0xffffffff){
timer_ptr = next_timer;
}
else{
timer_ptr = timer_ptr->timer_next;
}
}
//tmr_cb_ptr_array is no longer needed.
c_free(cb_reg_array);
//add suspended_timer_list pointer to swtimer table.
lua_pushstring(L, SUSP_LIST_STR);
lua_pushlightuserdata(L, suspended_timer_list_head);
lua_rawset(L, -3);
//pop swtimer table from stack
lua_pop(L, 1);
return;
}
void swtmr_resume_timers(){
lua_State* L = lua_getstate();
//get swtimer table
push_swtmr_registry_key(L);
lua_rawget(L, L_REGISTRY);
//get suspended_timer_list lightuserdata
lua_pushstring(L, SUSP_LIST_STR);
lua_rawget(L, -2);
//check for existence of swtimer table and the suspended_timer_list pointer userdata, return if not found
if(!lua_istable(L, -2) || !lua_isuserdata(L, -1)){
// not necessarily an error maybe there are legitimately no timers to resume
lua_pop(L, 2);
return;
}
os_timer_t* suspended_timer_list_ptr = lua_touserdata(L, -1);
lua_pop(L, 1); //pop suspended timer list userdata from stack
//since timers will be resumed, the suspended_timer_list lightuserdata can be cleared from swtimer table
lua_pushstring(L, SUSP_LIST_STR);
lua_pushnil(L);
lua_rawset(L, -3);
lua_pop(L, 1); //pop swtimer table from stack
volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
//this section does the actual resuming of the suspended timer(s)
while(suspended_timer_list_ptr != NULL){
os_timer_t* timer_list_ptr = timer_list;
//the pointer to next suspended timer must be saved, the current suspended timer will be removed from the list
os_timer_t* next_suspended_timer_ptr = suspended_timer_list_ptr->timer_next;
suspended_timer_list_ptr->timer_expire += frc2_count;
//traverse timer_list to determine where to insert suspended timer
while(timer_list_ptr != NULL){
if(suspended_timer_list_ptr->timer_expire > timer_list_ptr->timer_expire){
if(timer_list_ptr->timer_next != NULL){
//current timer is not at tail of timer_list
if(suspended_timer_list_ptr->timer_expire < timer_list_ptr->timer_next->timer_expire){
//insert suspended timer between current timer and next timer
suspended_timer_list_ptr->timer_next = timer_list_ptr->timer_next;
timer_list_ptr->timer_next = suspended_timer_list_ptr;
break; //timer resumed exit while loop
}
else{
//suspended timer expire is larger than next timer
}
}
else{
//current timer is at tail of timer_list and suspended timer expire is greater then current timer
//append timer to end of timer_list
timer_list_ptr->timer_next = suspended_timer_list_ptr;
suspended_timer_list_ptr->timer_next = NULL;
break; //timer resumed exit while loop
}
}
else if(timer_list_ptr == timer_list){
//insert timer at head of list
suspended_timer_list_ptr->timer_next = timer_list_ptr;
timer_list = timer_list_ptr = suspended_timer_list_ptr;
break; //timer resumed exit while loop
}
//suspended timer expire is larger than next timer
//timer not resumed, next timer in timer_list
timer_list_ptr = timer_list_ptr->timer_next;
}
//timer was resumed, next suspended timer
suspended_timer_list_ptr = next_suspended_timer_ptr;
}
return;
}
//this function registers a timer callback pointer in a lua table
void swtmr_cb_register(void* timer_cb_ptr, uint8 suspend_policy){
lua_State* L = lua_getstate();
if(!L){
//Lua has not started yet, therefore L_REGISTRY is not available.
//add timer cb to queue for later processing after Lua has started
add_to_reg_queue(timer_cb_ptr, suspend_policy);
return;
}
if(timer_cb_ptr){
size_t cb_list_last_idx = 0;
push_swtmr_registry_key(L);
lua_rawget(L, L_REGISTRY);
if(!lua_istable(L, -1)){
//swtmr does not exist, create and add to registry
lua_pop(L, 1);
lua_newtable(L);//push new table for swtmr.timer_cb_list
// add swtimer table to L_REGISTRY
push_swtmr_registry_key(L);
lua_pushvalue(L, -2);
lua_rawset(L, L_REGISTRY);
}
lua_pushstring(L, CB_LIST_STR);
lua_rawget(L, -2);
if(lua_istable(L, -1)){
//cb_list exists, get length of list
cb_list_last_idx = lua_objlen(L, -1);
}
else{
//cb_list does not exist in swtmr, create and add to swtmr
lua_pop(L, 1);// pop nil value from stack
lua_newtable(L);//create new table for swtmr.timer_cb_list
lua_pushstring(L, CB_LIST_STR); //push name for the new table onto the stack
lua_pushvalue(L, -2); //push table to top of stack
lua_rawset(L, -4); //pop table and name from stack and register in swtmr
}
//append new timer cb ptr to table
lua_pushnumber(L, cb_list_last_idx+1);
cb_registry_item_t* reg_item = lua_newuserdata(L, sizeof(cb_registry_item_t));
reg_item->tmr_cb_ptr = timer_cb_ptr;
reg_item->suspend_policy = suspend_policy;
lua_rawset(L, -3);
//clear items pushed onto stack by this function
lua_pop(L, 2);
}
return;
}
//this function adds the timer cb ptr to a queue for later registration after lua has started
static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy){
if(!timer_cb_ptr)
return;
tmr_cb_queue_t* queue_temp = c_zalloc(sizeof(tmr_cb_queue_t));
if(!queue_temp){
//it's boot time currently and we're already out of memory, something is very wrong...
dbg_printf("\n\t%s:out of memory, rebooting.", __FUNCTION__);
system_restart();
}
queue_temp->tmr_cb_ptr = timer_cb_ptr;
queue_temp->suspend_policy = suspend_policy;
queue_temp->next = NULL;
if(register_queue == NULL){
register_queue = queue_temp;
}
else{
tmr_cb_queue_t* queue_ptr = register_queue;
while(queue_ptr->next != NULL){
queue_ptr = queue_ptr->next;
}
queue_ptr->next = queue_temp;
}
if(!cb_register_task_id){
cb_register_task_id = task_get_id(process_cb_register_queue);//get task id from task interface
task_post_low(cb_register_task_id, false); //post task to process next item in queue
}
return;
}
static void process_cb_register_queue(task_param_t param, uint8 priority)
{
if(!lua_getstate()){
SWTMR_DBG("L== NULL, Lua not yet started! posting task");
task_post_low(cb_register_task_id, false); //post task to process next item in queue
return;
}
while(register_queue != NULL){
tmr_cb_queue_t* register_queue_ptr = register_queue;
void* cb_ptr_tmp = register_queue_ptr->tmr_cb_ptr;
swtmr_cb_register(cb_ptr_tmp, register_queue_ptr->suspend_policy);
register_queue = register_queue->next;
c_free(register_queue_ptr);
}
return;
}
#ifdef SWTMR_DEBUG
int print_timer_list(lua_State* L){
push_swtmr_registry_key(L);
lua_rawget(L, L_REGISTRY);
lua_pushstring(L, CB_LIST_STR);
lua_rawget(L, -2);
if(!lua_istable(L, -2) || !lua_istable(L, -1)){
lua_pop(L, 2);
return 0;
}
os_timer_t* suspended_timer_list_head = NULL;
os_timer_t* suspended_timer_list_tail = NULL;
lua_pushstring(L, SUSP_LIST_STR);
lua_rawget(L, -3);
if(lua_isuserdata(L, -1)){
suspended_timer_list_head = suspended_timer_list_tail = lua_touserdata(L, -1);
while(suspended_timer_list_tail->timer_next != NULL){
suspended_timer_list_tail = suspended_timer_list_tail->timer_next;
}
}
lua_pop(L, 1);
size_t registered_cb_qty = lua_objlen(L, -1);
cb_registry_item_t** cb_reg_array = c_zalloc(sizeof(cb_registry_item_t*)*registered_cb_qty);
if(!cb_reg_array){
luaL_error(L, "%s: unable to suspend timers, out of memory!", __func__);
return 0;
}
uint8 index = 0;
lua_pushnil(L);
while(lua_next(L, -2) != 0){
if(lua_isuserdata(L, -1)){
cb_reg_array[index] = lua_touserdata(L, -1);
}
lua_pop(L, 1);
index++;
}
lua_pop(L, 1);
os_timer_t* timer_list_ptr = timer_list;
dbg_printf("\n\tCurrent FRC2: %u\n", RTC_REG_READ(FRC2_COUNT_ADDRESS));
dbg_printf("\ttimer_list:\n");
while(timer_list_ptr != NULL){
bool registered_flag = FALSE;
for(int i=0; i < registered_cb_qty; i++){
if(timer_list_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){
registered_flag = TRUE;
break;
}
}
dbg_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\t%s\n",
timer_list_ptr, timer_list_ptr->timer_func, timer_list_ptr->timer_expire, timer_list_ptr->timer_period, timer_list_ptr->timer_next, registered_flag ? "Registered" : "");
timer_list_ptr = timer_list_ptr->timer_next;
}
c_free(cb_reg_array);
lua_pop(L, 1);
return 0;
}
int print_susp_timer_list(lua_State* L){
push_swtmr_registry_key(L);
lua_rawget(L, L_REGISTRY);
if(!lua_istable(L, -1)){
return luaL_error(L, "swtmr table not found!");
}
lua_pushstring(L, SUSP_LIST_STR);
lua_rawget(L, -2);
if(!lua_isuserdata(L, -1)){
return luaL_error(L, "swtmr.suspended_list userdata not found!");
}
os_timer_t* susp_timer_list_ptr = lua_touserdata(L, -1);
dbg_printf("\n\tsuspended_timer_list:\n");
while(susp_timer_list_ptr != NULL){
dbg_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\n",susp_timer_list_ptr, susp_timer_list_ptr->timer_func, susp_timer_list_ptr->timer_expire, susp_timer_list_ptr->timer_period, susp_timer_list_ptr->timer_next);
susp_timer_list_ptr = susp_timer_list_ptr->timer_next;
}
return 0;
}
int suspend_timers_lua(lua_State* L){
swtmr_suspend_timers();
return 0;
}
int resume_timers_lua(lua_State* L){
swtmr_resume_timers();
return 0;
}
static const LUA_REG_TYPE test_swtimer_debug_map[] = {
{ LSTRKEY( "timer_list" ), LFUNCVAL( print_timer_list ) },
{ LSTRKEY( "susp_timer_list" ), LFUNCVAL( print_susp_timer_list ) },
{ LSTRKEY( "suspend" ), LFUNCVAL( suspend_timers_lua ) },
{ LSTRKEY( "resume" ), LFUNCVAL( resume_timers_lua ) },
{ LNILKEY, LNILVAL }
};
NODEMCU_MODULE(SWTMR_DBG, "SWTMR_DBG", test_swtimer_debug_map, NULL);
#endif
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "c_string.h" #include "c_string.h"
#include "user_interface.h" #include "user_interface.h"
#include "smart.h" #include "smart.h"
#include "pm/swtimer.h"
#define ADDR_MAP_NUM 10 #define ADDR_MAP_NUM 10
...@@ -500,6 +501,9 @@ void smart_end(){ ...@@ -500,6 +501,9 @@ void smart_end(){
os_timer_disarm(&smart_timer); os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)1); os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)1);
SWTIMER_REG_CB(station_check_connect, SWTIMER_RESUME);
//the function station_check_connect continues the Smart config process and fires the developers callback upon successful connection to the access point.
//If this function manages to get suspended, I think it would be fine to resume the timer.
os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat
} }
} }
...@@ -672,6 +676,9 @@ void smart_begin(int chnl, smart_succeed s, void *arg){ ...@@ -672,6 +676,9 @@ void smart_begin(int chnl, smart_succeed s, void *arg){
wifi_set_promiscuous_rx_cb(detect); wifi_set_promiscuous_rx_cb(detect);
os_timer_disarm(&smart_timer); os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL); os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL);
SWTIMER_REG_CB(smart_next_channel, SWTIMER_RESUME);
//smart_next_channel switches the wifi channel
//I don't see a problem with resuming this timer
os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0); // no repeat os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0); // no repeat
if(s){ if(s){
...@@ -717,5 +724,6 @@ void station_check_connect(bool smart){ ...@@ -717,5 +724,6 @@ void station_check_connect(bool smart){
} }
os_timer_disarm(&smart_timer); os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)(int)smart); os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)(int)smart);
//this function was already registered in the function smart_end.
os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat
} }
#############################################################
# 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
/* 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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment