Browse Source

Refactor timer suspend portion of node.sleep (pmsleep) (#2287)

* pmsleep refactor
* Shortened swtmr disabled message 
* Added swtimer debug module option to user_modules.h.
* Added comments to user_config.h.
* Fixed error in documentation for node.sleep()
* remove blank sntp.c that got added in during rebase onto dev(6218b92)
* Added #ifdefs around SWTIMER_REG_CB to prevent inclusion of disabled
code
dnc40085 6 years ago
parent
commit
96e5c026a8

+ 0 - 4
app/Makefile

@@ -46,8 +46,6 @@ SUBDIRS= 					\
 	fatfs					\
 	esp-gdbstub				\
 	websocket				\
-	swTimer					\
-	misc					\
 	pm					\
 	sjson					\
  	sqlite3					\
@@ -102,8 +100,6 @@ COMPONENTS_eagle.app.v6 = 			\
 	net/libnodemcu_net.a			\
 	mbedtls/libmbedtls.a      		\
 	modules/libmodules.a			\
-	swTimer/libswtimer.a			\
-	misc/libmisc.a				\
 	sjson/libsjson.a			\
   sqlite3/libsqlite3.a			\
 	

+ 3 - 0
app/coap/coap_timer.c

@@ -1,6 +1,7 @@
 #include "node.h"
 #include "coap_timer.h"
 #include "os_type.h"
+#include "pm/swtimer.h"
 
 static os_timer_t coap_timer;
 static coap_tick_t basetime = 0;
@@ -48,6 +49,8 @@ void coap_timer_tick(void *arg){
 void coap_timer_setup(coap_queue_t ** queue, coap_tick_t t){
   os_timer_disarm(&coap_timer);
   os_timer_setfn(&coap_timer, (os_timer_func_t *)coap_timer_tick, queue);
+  SWTIMER_REG_CB(coap_timer_tick, SWTIMER_RESUME);
+    //coap_timer_tick processes a queue, my guess is that it is ok to resume the timer from where it left off
   os_timer_arm(&coap_timer, t, 0);   // no repeat
 }
 

+ 5 - 0
app/driver/key.c

@@ -14,6 +14,7 @@
 #include "mem.h"
 #include "gpio.h"
 #include "user_interface.h"
+#include "pm/swtimer.h"
 
 #include "driver/key.h"
 
@@ -148,6 +149,8 @@ key_intr_handler(void *arg)
                 // 5s, restart & enter softap mode
                 os_timer_disarm(&keys->single_key[i]->key_5s);
                 os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);
+                SWTIMER_REG_CB(key_5s_cb, SWTIMER_DROP);
+                  // key_5s_cb checks the state of a gpio. After resume, gpio state would be invalid
                 os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);
                 keys->single_key[i]->key_level = 0;
                 gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);
@@ -155,6 +158,8 @@ key_intr_handler(void *arg)
                 // 50ms, check if this is a real key up
                 os_timer_disarm(&keys->single_key[i]->key_50ms);
                 os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);
+                SWTIMER_REG_CB(key_50ms_cb, SWTIMER_DROP);
+                  // key_50ms_cb checks the state of a gpio. After resume, gpio state would be invalid
                 os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);
             }
         }

+ 3 - 0
app/driver/spi.c

@@ -527,6 +527,7 @@ void spi_slave_init(uint8 spi_no)
 
 
 #ifdef SPI_SLAVE_DEBUG
+#include "pm/swtimer.h"
  /******************************************************************************
  * FunctionName : hspi_master_readwrite_repeat
  * Description  : SPI master test  function for reading and writing esp8266 slave buffer,
@@ -545,6 +546,8 @@ void hspi_master_readwrite_repeat(void)
 	temp++;
 	spi_byte_write_espslave(SPI_HSPI,temp);
        os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);
+       SWTIMER_REGISTER_CB_PTR(hspi_master_readwrite_repeat, SWTIMER_RESUME);
+         //hspi_master_readwrite_repeat timer will be resumed on wake up, maybe data will still be in buffer?
        os_timer_arm(&timer2, 500, 0);
 }
 #endif

+ 3 - 0
app/driver/uart.c

@@ -323,11 +323,14 @@ uart_autobaud_timeout(void *timer_arg)
     uart_div_modify(uart_no, divisor);
   }
 }
+#include "pm/swtimer.h"
 
 static void 
 uart_init_autobaud(uint32_t uart_no)
 {
   os_timer_setfn(&autobaud_timer, uart_autobaud_timeout, (void *) uart_no);
+  SWTIMER_REG_CB(uart_autobaud_timeout, SWTIMER_DROP);
+    //if autobaud hasn't done it's thing by the time light sleep triggered, it probably isn't going to happen.
   os_timer_arm(&autobaud_timer, 100, TRUE);
 }
 

+ 3 - 0
app/http/httpclient.c

@@ -20,6 +20,7 @@
 #include "limits.h"
 #include "httpclient.h"
 #include "stdlib.h"
+#include "pm/swtimer.h"
 
 #define REDIRECTION_FOLLOW_MAX 20
 
@@ -525,6 +526,8 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_
 		/* Set connection timeout timer */
 		os_timer_disarm( &(req->timeout_timer) );
 		os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn );
+		SWTIMER_REG_CB(http_timeout_callback, SWTIMER_IMMEDIATE);
+		  //http_timeout_callback frees memory used by this function and timer cannot be dropped
 		os_timer_arm( &(req->timeout_timer), req->timeout, false );
 
 #ifdef CLIENT_SSL_ENABLE

+ 0 - 40
app/include/misc/dynarr.h

@@ -1,40 +0,0 @@
-#ifndef __DYNARR_H__
-#define __DYNARR_H__
-#include "user_interface.h"
-#include "c_stdio.h"
-#include "c_stdlib.h"
-
-//#define DYNARR_DEBUG
-//#define DYNARR_ERROR
-
-
-typedef struct _dynarr{
-  void* data_ptr;
-  size_t used;
-  size_t array_size;
-  size_t data_size;
-} dynarr_t;
-
-bool dynarr_init(dynarr_t* array_ptr, size_t array_size, size_t data_size);
-bool dynarr_resize(dynarr_t* array_ptr, size_t elements_to_add);
-bool dynarr_remove(dynarr_t* array_ptr, void* element_ptr);
-bool dynarr_add(dynarr_t* array_ptr, void* data_ptr, size_t data_size);
-bool dynarr_boundaryCheck(dynarr_t* array_ptr, void* element_ptr);
-bool dynarr_free(dynarr_t* array_ptr);
-
-
-#if 0 || defined(DYNARR_DEBUG) || defined(NODE_DEBUG)
-#define DYNARR_DBG(fmt, ...) c_printf("\n DYNARR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DYNARR_DBG(...)
-
-#endif
-
-#if 0 || defined(DYNARR_ERROR) || defined(NODE_ERROR)
-#define DYNARR_ERR(fmt, ...) c_printf("\n DYNARR: "fmt"\n", ##__VA_ARGS__)
-#else
-#define DYNARR_ERR(...)
-
-#endif
-
-#endif // __DYNARR_H__

+ 0 - 0
app/pm/pmSleep.h → app/include/pm/pmSleep.h


+ 30 - 0
app/include/pm/swtimer.h

@@ -0,0 +1,30 @@
+/*
+ * swtimer.h
+ *
+ *  Created on: Aug 4, 2017
+ *      Author: anonymous
+ */
+
+#ifndef APP_INCLUDE_PM_SWTIMER_H_
+#define APP_INCLUDE_PM_SWTIMER_H_
+
+void swtmr_cb_register(void* timer_cb_ptr, uint8 suspend_policy);
+
+#define SWTIMER_RESUME    0 //save remaining time
+#define SWTIMER_RESTART   1 //use timer_period as remaining time
+#define SWTIMER_IMMEDIATE 2 //fire timer immediately after resume
+#define SWTIMER_DROP      3 //disarm timer, do not resume
+
+#if defined(TIMER_SUSPEND_ENABLE)
+#define SWTIMER_REG_CB(cb_ptr, suspend_policy) do{ \
+    static bool cb_ptr##_registered_flag;\
+    if(!cb_ptr##_registered_flag){ \
+      cb_ptr##_registered_flag = true; \
+      swtmr_cb_register(cb_ptr, suspend_policy);\
+    } \
+}while(0);
+#else
+#define SWTIMER_REG_CB(...)
+#endif
+
+#endif /* APP_INCLUDE_PM_SWTIMER_H_ */

+ 4 - 0
app/include/rtc/rtctime_internal.h

@@ -689,11 +689,15 @@ static inline void rtc_time_switch_to_system_clock(void)
 
 static inline void rtc_time_tmrfn(void* arg);
 
+#include "pm/swtimer.h"
+
 static void rtc_time_install_timer(void)
 {
   static ETSTimer tmr;
 
   os_timer_setfn(&tmr,rtc_time_tmrfn,NULL);
+  SWTIMER_REG_CB(rtc_time_tmrfn, SWTIMER_RESUME);
+    //I believe the function rtc_time_tmrfn compensates for drift in the clock and updates rtc time accordingly, This timer should probably be resumed
   os_timer_arm(&tmr,10000,1);
 }
 

+ 0 - 53
app/include/swTimer/swTimer.h

@@ -1,53 +0,0 @@
-#ifndef __SW_TIMER_H__
-#define __SW_TIMER_H__
-#include "user_interface.h"
-//#define SWTMR_DEBUG
-#define USE_SWTMR_ERROR_STRINGS
-
-#if defined(DEVELOP_VERSION)
-#define SWTMR_DEBUG
-#endif
-
-#if defined(SWTMR_DEBUG)
-  #define SWTMR_DBG(fmt, ...) dbg_printf("\tSWTIMER(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__)
-#else
-  #define SWTMR_DBG(...)
-#endif
-
-#if defined(NODE_ERROR)
-  #define SWTMR_ERR(fmt, ...) NODE_ERR("%s"fmt"\n", "SWTIMER:", ##__VA_ARGS__)
-#else
-  #define SWTMR_ERR(...)
-#endif
-
-enum SWTMR_STATUS{
-  SWTMR_FAIL = 0,
-  SWTMR_OK = 1,
-
-  SWTMR_MALLOC_FAIL = 10,
-  SWTMR_TIMER_NOT_ARMED,
-//  SWTMR_NULL_PTR,
-
-  SWTMR_REGISTRY_NO_REGISTERED_TIMERS,
-
-//  SWTMR_SUSPEND_ARRAY_INITIALIZATION_FAILED,
-//  SWTMR_SUSPEND_ARRAY_ADD_FAILED,
-//  SWTMR_SUSPEND_ARRAY_REMOVE_FAILED,
-  SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED,
-  SWTMR_SUSPEND_TIMER_ALREADY_REARMED,
-  SWTMR_SUSPEND_NO_SUSPENDED_TIMERS,
-  SWTMR_SUSPEND_TIMER_NOT_SUSPENDED,
-
-};
-
-/*      Global Function Declarations      */
-void swtmr_register(void* timer_ptr);
-void swtmr_unregister(void* timer_ptr);
-int swtmr_suspend(os_timer_t* timer_ptr);
-int swtmr_resume(os_timer_t* timer_ptr);
-void swtmr_print_registry(void);
-void swtmr_print_suspended(void);
-void swtmr_print_timer_list(void);
-const char* swtmr_errorcode2str(int error_value);
-bool swtmr_suspended_test(os_timer_t* timer_ptr);
-#endif // __SW_TIMER_H__

+ 2 - 2
app/include/user_config.h

@@ -116,8 +116,8 @@ extern void luaL_assertfail(const char *file, int line, const char *message);
 #define WIFI_SDK_EVENT_MONITOR_ENABLE
 #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
 
-////#define ENABLE_TIMER_SUSPEND
-//#define PMSLEEP_ENABLE
+//#define PMSLEEP_ENABLE // Enable wifi.suspend() and node.sleep() (NOTE: node.sleep() is dependent on TIMER_SUSPEND_ENABLE)
+//#define TIMER_SUSPEND_ENABLE //Required by node.sleep()
 
 
 #define STRBUF_DEFAULT_INCREMENT 32

+ 4 - 0
app/include/user_modules.h

@@ -86,5 +86,9 @@
 //#define LUA_USE_MODULES_WS2812_EFFECTS
 //#define LUA_USE_MODULES_XPT2046
 
+//debug modules
+//#define LUA_USE_MODULES_SWTMR_DBG //SWTMR timer suspend Debug functions
+
+
 #endif  /* LUA_CROSS_COMPILER */
 #endif	/* __USER_MODULES_H__ */

+ 3 - 0
app/lwip/core/mdns.c

@@ -1039,6 +1039,7 @@ mdns_reg(struct mdns_info *info) {
 	   os_timer_disarm(&mdns_timer);
    }
 }
+#include "pm/swtimer.h"
 
 /**
  * Initialize the resolver: set up the UDP pcb and configure the default server
@@ -1129,6 +1130,8 @@ mdns_init(struct mdns_info *info) {
 
 		os_timer_disarm(&mdns_timer);
 		os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
+		SWTIMER_REG_CB(mdns_reg, SWTIMER_RESTART);
+		  //going on the above comment, it's probably a good idea to let mdns_reg run it's course. not sure if the 1 second timing is important, so lets restart it to be safe.
 		os_timer_arm(&mdns_timer, 1000, 1);
 	}
 }

+ 0 - 52
app/misc/Makefile

@@ -1,52 +0,0 @@
-
-#############################################################
-# Required variables for each makefile
-# Discard this section from all parent makefiles
-# Expected variables (with automatic defaults):
-#   CSRCS (all "C" files in the dir)
-#   SUBDIRS (all subdirs with a Makefile)
-#   GEN_LIBS - list of libs to be generated ()
-#   GEN_IMAGES - list of images to be generated ()
-#   COMPONENTS_xxx - a list of libs/objs in the form
-#     subdir/lib to be extracted and rolled up into
-#     a generated lib/image xxx.a ()
-#
-ifndef PDIR
-GEN_LIBS = libmisc.a
-endif
-
-STD_CFLAGS=-std=gnu11 -Wimplicit
-
-#############################################################
-# Configuration i.e. compile options etc.
-# Target specific stuff (defines etc.) goes in here!
-# Generally values applying to a tree are captured in the
-#   makefile at its root level - these are then overridden
-#   for a subtree within the makefile rooted therein
-#
-#DEFINES += 
-
-#############################################################
-# Recursion Magic - Don't touch this!!
-#
-# Each subtree potentially has an include directory
-#   corresponding to the common APIs applicable to modules
-#   rooted at that subtree. Accordingly, the INCLUDE PATH
-#   of a module can only contain the include directories up
-#   its parent path, and not its siblings
-#
-# Required for each makefile to inherit from the parent
-#
-
-INCLUDES := $(INCLUDES) -I $(PDIR)include
-INCLUDES += -I ./
-INCLUDES += -I ./include
-INCLUDES += -I ../include
-INCLUDES += -I ../../include
-INCLUDES += -I ../lua
-INCLUDES += -I ../platform
-INCLUDES += -I ../libc
-
-PDIR := ../$(PDIR)
-sinclude $(PDIR)Makefile
-

+ 0 - 131
app/misc/dyn_arr.c

@@ -1,131 +0,0 @@
-#include "misc/dynarr.h"
-
-#define ARRAY_PTR_CHECK if(array_ptr == NULL || array_ptr->data_ptr == NULL){\
-    /**/DYNARR_DBG("array not initialized");\
-    return false; \
-  }
-
-bool dynarr_init(dynarr_t* array_ptr, size_t array_size, size_t data_size){
-  if(array_ptr == NULL || data_size == 0 || array_size == 0){
-    /**/DYNARR_DBG("Invalid parameter: array_ptr(%p) data_size(%u) array_size(%u)", array_ptr, data_size, array_size);
-    return false;
-  }
-  if(array_ptr->data_ptr != NULL ){
-    /**/DYNARR_DBG("Array already initialized: array_ptr->data_ptr=%p", array_ptr->data_ptr);
-    return false;
-  }
-  /**/DYNARR_DBG("Array parameters:\n\t\t\tarray_size(%u)\n\t\t\tdata_size(%u)\n\t\t\ttotal size(bytes):%u", array_size, data_size, (array_size * data_size));
-
-  void* temp_array = c_zalloc(array_size * data_size);
-  if(temp_array == NULL){
-    /**/DYNARR_ERR("malloc FAIL! req:%u free:%u", (array_size * data_size), system_get_free_heap_size());
-    return false;
-  }
-
-  array_ptr->data_ptr = temp_array;
-  array_ptr->array_size = array_size;
-  array_ptr->data_size = data_size;
-  array_ptr->used = 0;
-
-  return true;
-}
-
-bool dynarr_resize(dynarr_t* array_ptr, size_t elements_to_add){
-  ARRAY_PTR_CHECK;
-
-  if(elements_to_add <= 0){
-    /**/DYNARR_DBG("Invalid qty: elements_to_add=%u", elements_to_add);
-    return false;
-  }
-
-  size_t new_array_size = array_ptr->array_size + elements_to_add;
-
-  /**/DYNARR_DBG("old size=%u\tnew size=%u\tmem used=%u",
-      array_ptr->array_size, new_array_size, (new_array_size * array_ptr->data_size));
-
-  void* temp_array_p = c_realloc(array_ptr->data_ptr, new_array_size * array_ptr->data_size);
-  if(temp_array_p == NULL){
-    /**/DYNARR_ERR("malloc FAIL! req:%u free:%u", (new_array_size * array_ptr->data_size), system_get_free_heap_size());
-    return false;
-  }
-
-  array_ptr->data_ptr = temp_array_p;
-
-  size_t prev_size = array_ptr->array_size;
-
-  array_ptr->array_size = new_array_size;
-
-  //set memory to 0 for newly added array elements
-  memset((uint8*) array_ptr->data_ptr + (prev_size * array_ptr->data_size), 0, (elements_to_add * array_ptr->data_size));
-
-  /**/DYNARR_DBG("Array successfully resized");
-  return true;
-}
-
-bool dynarr_remove(dynarr_t* array_ptr, void* element_to_remove){
-  ARRAY_PTR_CHECK;
-
-  uint8* element_ptr = element_to_remove;
-  uint8* data_ptr = array_ptr->data_ptr;
-
-  if(dynarr_boundaryCheck(array_ptr, element_to_remove) == FALSE){
-    return false;
-  }
-
-  //overwrite element to be removed by shifting all elements to the left
-  memmove(element_ptr, element_ptr + array_ptr->data_size,  (array_ptr->array_size - 1) * array_ptr->data_size - (element_ptr - data_ptr));
-
-  //clear newly freed element
-  memset(data_ptr + ((array_ptr->array_size-1) * array_ptr->data_size), 0, array_ptr->data_size);
-
-  //decrement array used since we removed an element
-  array_ptr->used--;
-  /**/DYNARR_DBG("element(%p) removed from array", element_ptr);
-  return true;
-}
-
-bool dynarr_add(dynarr_t* array_ptr, void* data_ptr, size_t data_size){
-  ARRAY_PTR_CHECK;
-
-  if(data_size != array_ptr->data_size){
-    /**/DYNARR_DBG("Invalid data size: data_size(%u) != arr->data_size(%u)", data_size, array_ptr->data_size);
-    return false;
-  }
-
-  if(array_ptr->array_size == array_ptr->used){
-    if(!dynarr_resize(array_ptr, (array_ptr->array_size/2))){
-      return false;
-    }
-  }
-  memcpy(((uint8*)array_ptr->data_ptr + (array_ptr->used * array_ptr->data_size)), data_ptr, array_ptr->data_size);
-
-  array_ptr->used++;
-  return true;
-}
-
-bool dynarr_boundaryCheck(dynarr_t* array_ptr, void* element_to_check){
-  ARRAY_PTR_CHECK;
-
-  uint8* data_ptr = array_ptr->data_ptr;
-  uint8* element_ptr = element_to_check;
-
-  if(element_ptr < data_ptr || ((element_ptr - data_ptr) / array_ptr->data_size) > array_ptr->array_size - 1){
-    /**/DYNARR_DBG("element_ptr(%p) out of bounds: first element ptr:%p last element ptr:%p",
-        element_ptr, data_ptr, data_ptr + ((array_ptr->array_size - 1) * array_ptr->data_size));
-    return false;
-  }
-  return true;
-}
-
-bool dynarr_free(dynarr_t* array_ptr){
-  ARRAY_PTR_CHECK;
-
-  c_free(array_ptr->data_ptr);
-
-  array_ptr->data_ptr=NULL;
-  array_ptr->array_size = array_ptr->used = 0;
-
-  /**/DYNARR_DBG("array freed");
-  return true;
-}
-

+ 9 - 5
app/modules/cron.c

@@ -190,7 +190,7 @@ static void cron_handle_tmr() {
   struct rtc_timeval tv;
   rtctime_gettimeofday(&tv);
   if (tv.tv_sec == 0) { // Wait for RTC time
-    ets_timer_arm_new(&cron_timer, 1000, 0, 1);
+    os_timer_arm(&cron_timer, 1000, 0);
     return;
   }
   time_t t = tv.tv_sec;
@@ -202,7 +202,7 @@ static void cron_handle_tmr() {
     diff += 60000;
     gmtime_r(&t, &tm);
   }
-  ets_timer_arm_new(&cron_timer, diff, 0, 1);
+  os_timer_arm(&cron_timer, diff, 0);
   cron_handle_time(tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, tm.tm_hour, tm.tm_min);
 }
 
@@ -220,11 +220,15 @@ static const LUA_REG_TYPE cron_map[] = {
   { LSTRKEY( "reset" ),      LFUNCVAL( lcron_reset ) },
   { LNILKEY, LNILVAL }
 };
+#include "pm/swtimer.h"
 
 int luaopen_cron( lua_State *L ) {
-  ets_timer_disarm(&cron_timer);
-  ets_timer_setfn(&cron_timer, cron_handle_tmr, 0);
-  ets_timer_arm_new(&cron_timer, 1000, 0, 1);
+  os_timer_disarm(&cron_timer);
+  os_timer_setfn(&cron_timer, cron_handle_tmr, 0);
+  SWTIMER_REG_CB(cron_handle_tmr, SWTIMER_RESTART);
+    //cron_handle_tmr determines when to execute a scheduled cron job
+    //My guess: To be sure to give the other modules required by cron enough time to get to a ready state, restart cron_timer.
+  os_timer_arm(&cron_timer, 1000, 0);
   luaL_rometatable(L, "cron.entry", (void *)cronent_map);
   return 0;
 }

+ 5 - 0
app/modules/ds18b20.c

@@ -134,6 +134,8 @@ static int ds18b20_lua_setting(lua_State *L) {
 	return 0;
 }
 
+#include "pm/swtimer.h"
+
 // Reads sensor values from all devices
 // Lua: 	ds18b20.read(function(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) print(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) end, ROM[, FAMILY])
 static int ds18b20_lua_read(lua_State *L) {
@@ -173,6 +175,9 @@ static int ds18b20_lua_read(lua_State *L) {
 	onewire_write(ds18b20_bus_pin, DS18B20_ROM_SKIP, 0);
 	onewire_write(ds18b20_bus_pin, DS18B20_FUNC_CONVERT, 1);
 	os_timer_setfn(&ds18b20_timer, (os_timer_func_t *)ds18b20_lua_readoutdone, NULL);
+	SWTIMER_REG_CB(ds18b20_lua_readoutdone, SWTIMER_DROP);
+		//The function ds18b20_lua_readoutdone reads the temperature from the sensor(s) after a set amount of time depending on temperature resolution
+	  //MY guess: If this timer manages to get suspended before it fires and the temperature data is time sensitive then resulting data would be invalid and should be discarded
 	
 	switch (ds18b20_device_res) {
 		case (9):

+ 7 - 1
app/modules/enduser_setup.c

@@ -212,12 +212,15 @@ static void enduser_setup_connected_callback()
   }
 }
 
-
+#include "pm/swtimer.h"
 static void enduser_setup_check_station_start(void)
 {
   ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start");
 
   os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL);
+  SWTIMER_REG_CB(enduser_setup_check_station, SWTIMER_RESUME);
+    //The function enduser_setup_check_station checks for a successful connection to the configured AP
+    //My guess: I'm not sure about whether or not user feedback is given via the web interface, but I don't see a problem with letting this timer resume.
   os_timer_arm(&(state->check_station_timer), 3*1000, TRUE);
 }
 
@@ -317,6 +320,9 @@ static void enduser_setup_check_station(void *p)
   if (!manual)
   {
     os_timer_setfn(&(state->shutdown_timer), enduser_setup_stop_callback, NULL);
+    SWTIMER_REG_CB(enduser_setup_stop_callback, SWTIMER_RESUME);
+      //The function enduser_setup_stop_callback frees services and resources used by enduser setup.
+      //My guess: Since it would lead to a memory leak, it's probably best to resume this timer.
     os_timer_arm(&(state->shutdown_timer), 10*1000, FALSE);
   }
 }

+ 4 - 0
app/modules/mqtt.c

@@ -981,6 +981,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
   return espconn_status;
 }
 
+#include "pm/swtimer.h"
 // Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client), function(client, connect_return_code) )
 static int mqtt_socket_connect( lua_State* L )
 {
@@ -1114,6 +1115,9 @@ static int mqtt_socket_connect( lua_State* L )
 
   os_timer_disarm(&mud->mqttTimer);
   os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud);
+  SWTIMER_REG_CB(mqtt_socket_timer, SWTIMER_RESUME);
+    //I assume that mqtt_socket_timer connects to the mqtt server, but I'm not really sure what impact light_sleep will have on it.
+    //My guess: If in doubt, resume the timer
   // timer started in socket_connect()
 
   if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0))

+ 6 - 1
app/modules/node.c

@@ -76,7 +76,7 @@ static int node_deepsleep( lua_State* L )
 
 
 #ifdef PMSLEEP_ENABLE
-#include "pmSleep.h"
+#include "pm/pmSleep.h"
 
 int node_sleep_resume_cb_ref= LUA_NOREF;
 void node_sleep_resume_cb(void)
@@ -89,6 +89,7 @@ void node_sleep_resume_cb(void)
 // Lua: node.sleep(table)
 static int node_sleep( lua_State* L )
 {
+#ifdef TIMER_SUSPEND_ENABLE
   pmSleep_INIT_CFG(cfg);
   cfg.sleep_mode=LIGHT_SLEEP_T;
 
@@ -101,6 +102,10 @@ static int node_sleep( lua_State* L )
 
   cfg.resume_cb_ptr = &node_sleep_resume_cb;
   pmSleep_suspend(&cfg);
+#else
+  c_printf("\n The option \"timer_suspend_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n");
+  return luaL_error(L, "light sleep is unavailable");
+#endif
   return 0;
 }
 #endif //PMSLEEP_ENABLE

+ 7 - 0
app/modules/rotary.c

@@ -129,6 +129,8 @@ int platform_rotary_exists( unsigned int id )
   return (id < ROTARY_CHANNEL_COUNT);
 }
 
+#include "pm/swtimer.h"
+
 // Lua: setup(id, phase_a, phase_b [, press])
 static int lrotary_setup( lua_State* L )
 {
@@ -155,6 +157,11 @@ static int lrotary_setup( lua_State* L )
   d->id = id;
 
   os_timer_setfn(&d->timer, lrotary_timer_done, (void *) d);
+  SWTIMER_REG_CB(lrotary_timer_done, SWTIMER_RESUME);
+    //lrotary_timer_done checks time elapsed since last event
+    //My guess: Since proper functionality relies on some variables to be reset via timer callback and state would be invalid anyway.
+      //It is probably best to resume this timer so it can reset it's state variables
+
   
   int i;
   for (i = 0; i < CALLBACK_COUNT; i++) {

+ 7 - 0
app/modules/sntp.c

@@ -319,6 +319,7 @@ static void sntp_handle_result(lua_State *L) {
   }
 }
 
+#include "pm/swtimer.h"
 
 static void sntp_dosend ()
 {
@@ -326,6 +327,9 @@ static void sntp_dosend ()
     if (state->server_pos < 0) {
       os_timer_disarm(&state->timer);
       os_timer_setfn(&state->timer, on_timeout, NULL);
+      SWTIMER_REG_CB(on_timeout, SWTIMER_RESUME);
+        //The function on_timeout calls this function(sntp_dosend) again to handle time sync timeout.
+        //My guess: Since the WiFi connection is restored after waking from light sleep, it would be possible to contact the SNTP server, So why not let it
       state->server_pos = 0;
     } else {
       ++state->server_pos;
@@ -708,6 +712,9 @@ static char *set_repeat_mode(lua_State *L, bool enable)
     lua_rawgeti(L, LUA_REGISTRYINDEX, state->list_ref);
     repeat->list_ref = luaL_ref(L, LUA_REGISTRYINDEX);
     os_timer_setfn(&repeat->timer, on_long_timeout, NULL);
+    SWTIMER_REG_CB(on_long_timeout, SWTIMER_RESUME);
+      //The function on_long_timeout returns errors to the developer
+      //My guess: Error reporting is a good thing, resume the timer.
     os_timer_arm(&repeat->timer, 1000 * 1000, 1);
   } else {
     if (repeat) {

+ 24 - 78
app/modules/tmr.c

@@ -53,7 +53,7 @@ tmr.softwd(int)
 #include "platform.h"
 #include "c_types.h"
 #include "user_interface.h"
-#include "swTimer/swTimer.h"
+#include "pm/swtimer.h"
 
 #define TIMER_MODE_OFF 3
 #define TIMER_MODE_SINGLE 0
@@ -231,68 +231,23 @@ static int tmr_stop(lua_State* L){
 	return 1;  
 }
 
-#ifdef ENABLE_TIMER_SUSPEND
+#ifdef TIMER_SUSPEND_ENABLE
 
+#define TMR_SUSPEND_REMOVED_MSG "This feature has been removed, we apologize for any inconvenience this may have caused."
 static int tmr_suspend(lua_State* L){
-  timer_t tmr = tmr_get(L, 1);
-
-  if((tmr->mode & TIMER_IDLE_FLAG) == 1){
-    return luaL_error(L, "timer not armed");
-  }
-
-  int retval = swtmr_suspend(&tmr->os);
-
-  if(retval != SWTMR_OK){
-    return luaL_error(L, swtmr_errorcode2str(retval));
-  }
-  else{
-    lua_pushboolean(L, true);
-  }
-
-  return 1;
+  return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
 }
 
 static int tmr_resume(lua_State* L){
-  timer_t tmr = tmr_get(L, 1);
-
-  if(swtmr_suspended_test(&tmr->os) == FALSE){
-    return luaL_error(L, "timer not suspended");
-  }
-
-  int retval = swtmr_resume(&tmr->os);
-
-  if(retval != SWTMR_OK){
-    return luaL_error(L, swtmr_errorcode2str(retval));
-  }
-  else{
-  lua_pushboolean(L, true);
-  }
-  return 1;
+  return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
 }
 
-static int tmr_suspend_all (lua_State *L)
-{
-  sint32 retval = swtmr_suspend(NULL);
-  //  lua_pushnumber(L, swtmr_suspend(NULL));
-  if(retval!=SWTMR_OK){
-    return luaL_error(L, swtmr_errorcode2str(retval));
-  }
-  else{
-    lua_pushboolean(L, true);
-  }
-  return 1;
+static int tmr_suspend_all (lua_State *L){
+  return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
 }
 
-static int tmr_resume_all (lua_State *L)
-{
-  sint32 retval = swtmr_resume(NULL);
-  if(retval!=SWTMR_OK){
-    return luaL_error(L, swtmr_errorcode2str(retval));
-  }
-  else{
-    lua_pushboolean(L, true);
-  }
-  return 1;
+static int tmr_resume_all (lua_State *L){
+  return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
 }
 
 
@@ -343,12 +298,7 @@ static int tmr_state(lua_State* L){
 
   lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
   lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG));
-#ifdef ENABLE_TIMER_SUSPEND
-  lua_pushboolean(L, swtmr_suspended_test(&tmr->os));
-#else
-  lua_pushnil(L);
-#endif
-	return 3;
+	return 2;
 }
 
 /*I left the led comments 'couse I don't know
@@ -454,7 +404,7 @@ static const LUA_REG_TYPE tmr_dyn_map[] = {
 	{ LSTRKEY( "unregister" ),  LFUNCVAL( tmr_unregister ) },
 	{ LSTRKEY( "state" ),       LFUNCVAL( tmr_state ) },
 	{ LSTRKEY( "interval" ),    LFUNCVAL( tmr_interval) },
-#ifdef ENABLE_TIMER_SUSPEND
+#ifdef TIMER_SUSPEND_ENABLE
 	{ LSTRKEY( "suspend" ),      LFUNCVAL( tmr_suspend ) },
   { LSTRKEY( "resume" ),       LFUNCVAL( tmr_resume ) },
 #endif
@@ -463,15 +413,6 @@ static const LUA_REG_TYPE tmr_dyn_map[] = {
 	{ LNILKEY, LNILVAL }
 };
 
-#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG)
-static const LUA_REG_TYPE tmr_dbg_map[] = {
-    { LSTRKEY( "printRegistry" ),        LFUNCVAL( tmr_printRegistry ) },
-    { LSTRKEY( "printSuspended" ),        LFUNCVAL( tmr_printSuspended ) },
-    { LSTRKEY( "printTimerlist" ),        LFUNCVAL( tmr_printTimerlist ) },
-  { LNILKEY, LNILVAL }
-};
-#endif
-
 static const LUA_REG_TYPE tmr_map[] = {
 	{ LSTRKEY( "delay" ),        LFUNCVAL( tmr_delay ) },
 	{ LSTRKEY( "now" ),          LFUNCVAL( tmr_now ) },
@@ -482,7 +423,7 @@ static const LUA_REG_TYPE tmr_map[] = {
 	{ LSTRKEY( "alarm" ),        LFUNCVAL( tmr_alarm ) },
 	{ LSTRKEY( "start" ),        LFUNCVAL( tmr_start ) },
   { LSTRKEY( "stop" ),         LFUNCVAL( tmr_stop ) },
-#ifdef ENABLE_TIMER_SUSPEND
+#ifdef TIMER_SUSPEND_ENABLE
   { LSTRKEY( "suspend" ),      LFUNCVAL( tmr_suspend ) },
   { LSTRKEY( "suspend_all" ),  LFUNCVAL( tmr_suspend_all ) },
   { LSTRKEY( "resume" ),       LFUNCVAL( tmr_resume ) },
@@ -492,15 +433,13 @@ static const LUA_REG_TYPE tmr_map[] = {
 	{ LSTRKEY( "state" ),        LFUNCVAL( tmr_state ) },
 	{ LSTRKEY( "interval" ),     LFUNCVAL( tmr_interval ) },
 	{ LSTRKEY( "create" ),       LFUNCVAL( tmr_create ) },
-#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG)
-  { LSTRKEY( "debug" ),       LROVAL( tmr_dbg_map ) },
-#endif
 	{ LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
 	{ LSTRKEY( "ALARM_SEMI" ),   LNUMVAL( TIMER_MODE_SEMI ) },
 	{ LSTRKEY( "ALARM_AUTO" ),   LNUMVAL( TIMER_MODE_AUTO ) },
 	{ LNILKEY, LNILVAL }
 };
 
+#include "pm/swtimer.h"
 int luaopen_tmr( lua_State *L ){
 	int i;	
 
@@ -510,16 +449,23 @@ int luaopen_tmr( lua_State *L ){
 		alarm_timers[i].lua_ref = LUA_NOREF;
 		alarm_timers[i].self_ref = LUA_REFNIL;
 		alarm_timers[i].mode = TIMER_MODE_OFF;
-		//improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call.
-		ets_timer_disarm(&alarm_timers[i].os);
+		os_timer_disarm(&alarm_timers[i].os);
 	}
 	last_rtc_time=system_get_rtc_time(); // Right now is time 0
 	last_rtc_time_us=0;
 
-  //improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call.
-	ets_timer_disarm(&rtc_timer);
+	os_timer_disarm(&rtc_timer);
 	os_timer_setfn(&rtc_timer, rtc_callback, NULL);
 	os_timer_arm(&rtc_timer, 1000, 1);
+
+  SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME);
+  //The function rtc_callback calls the a function that calibrates the SoftRTC for drift in the esp8266's clock.
+  //My guess: after the duration of light_sleep there's bound to be some drift in the clock, so a calibration is due.
+  SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME);
+  //The function alarm_timer_common handles timers created by the developer via tmr.create().
+  //No reason not to resume the timers, so resume em'.
+
+
 	return 0;
 }
 

+ 18 - 7
app/modules/wifi.c

@@ -429,7 +429,7 @@ static int wifi_setmaxtxpower( lua_State* L )
 
 #ifdef PMSLEEP_ENABLE
 /* Begin WiFi suspend functions*/
-#include "pmSleep.h"
+#include <pm/pmSleep.h>
 
 static int wifi_resume_cb_ref = LUA_NOREF; // Holds resume callback reference
 static int wifi_suspend_cb_ref = LUA_NOREF; // Holds suspend callback reference
@@ -511,6 +511,19 @@ static int wifi_resume(lua_State* L)
 }
 
 /* End WiFi suspend functions*/
+#else
+static char *susp_note_str = "\n The option \"pmsleep_enable\" in \"app/include/user_config.h\" was disabled during FW build!\n";
+static char *susp_unavailable_str = "wifi.suspend is unavailable";
+
+static int wifi_suspend(lua_State* L){
+  c_sprintf("%s", susp_note_str);
+  return luaL_error(L, susp_unavailable_str);
+}
+
+static int wifi_resume(lua_State* L){
+  c_sprintf("%s", susp_note_str);
+  return luaL_error(L, susp_unavailable_str);
+}
 #endif
 
 // Lua: wifi.nullmodesleep()
@@ -963,7 +976,7 @@ static int wifi_station_config( lua_State* L )
 
     lua_State* L_temp = NULL;
 
-    lua_getfield(L, 1, "connected_cb");
+    lua_getfield(L, 1, "connect_cb");
     if (!lua_isnil(L, -1))
     {
       if (lua_isfunction(L, -1))
@@ -976,12 +989,12 @@ static int wifi_station_config( lua_State* L )
       }
       else
       {
-        return luaL_argerror(L, 1, "connected_cb:not function");
+        return luaL_argerror(L, 1, "connect_cb:not function");
       }
     }
     lua_pop(L, 1);
 
-    lua_getfield(L, 1, "disconnected_cb");
+    lua_getfield(L, 1, "disconnect_cb");
     if (!lua_isnil(L, -1))
     {
       if (lua_isfunction(L, -1))
@@ -994,7 +1007,7 @@ static int wifi_station_config( lua_State* L )
       }
       else
       {
-        return luaL_argerror(L, 1, "disconnected_cb:not function");
+        return luaL_argerror(L, 1, "disconnect_cb:not function");
       }
     }
     lua_pop(L, 1);
@@ -1910,10 +1923,8 @@ static const LUA_REG_TYPE wifi_map[] =  {
   { LSTRKEY( "setphymode" ),     LFUNCVAL( wifi_setphymode ) },
   { LSTRKEY( "getphymode" ),     LFUNCVAL( wifi_getphymode ) },
   { LSTRKEY( "setmaxtxpower" ),  LFUNCVAL( wifi_setmaxtxpower ) },
-#ifdef PMSLEEP_ENABLE
   { LSTRKEY( "suspend" ),        LFUNCVAL( wifi_suspend ) },
   { LSTRKEY( "resume" ),         LFUNCVAL( wifi_resume ) },
-#endif
   { LSTRKEY( "nullmodesleep" ),  LFUNCVAL( wifi_null_mode_auto_sleep ) },
 #ifdef WIFI_SMART_ENABLE 
   { LSTRKEY( "startsmart" ),     LFUNCVAL( wifi_start_smart ) },

+ 1 - 1
app/modules/ws2812_effects.c

@@ -8,7 +8,7 @@
 #include "user_interface.h"
 #include "driver/uart.h"
 #include "osapi.h"
-#include "swTimer/swTimer.h"
+#include "pm/swtimer.h"
 
 #include "ws2812.h"
 #include "color_utils.h"

+ 4 - 0
app/net/nodemcu_mdns.c

@@ -1056,6 +1056,7 @@ mdns_dup_info(const struct nodemcu_mdns_info *info) {
   return result;
 }
 
+#include "pm/swtimer.h"
 /**
  * Initialize the resolver: set up the UDP pcb and configure the default server
  * (NEW IP).
@@ -1130,6 +1131,9 @@ nodemcu_mdns_init(struct nodemcu_mdns_info *info) {
   //MDNS_DBG("About to start timer\n");
   os_timer_disarm(&mdns_timer);
   os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
+  SWTIMER_REG_CB(mdns_reg, SWTIMER_RESUME);
+    //the function mdns_reg registers the mdns device on the network
+    //My guess: Since wifi connection is restored after waking from light_sleep, the related timer would have no problem resuming it's normal function.
   os_timer_arm(&mdns_timer, 1000 * 280, 1);
   /* kick off the first one right away */
   mdns_reg_handler_restart();

+ 40 - 32
app/pm/pmSleep.c

@@ -1,8 +1,10 @@
-#include "pmSleep.h"
+#include <pm/pmSleep.h>
 #ifdef  PMSLEEP_ENABLE
 #define STRINGIFY_VAL(x) #x
 #define STRINGIFY(x) STRINGIFY_VAL(x)
 
+//TODO: figure out why timed light_sleep doesn't work
+
 //holds duration error string
 //uint32 PMSLEEP_SLEEP_MAX_TIME=FPM_SLEEP_MAX_TIME-1;
 const char *PMSLEEP_DURATION_ERR_STR="duration: 0 or "STRINGIFY(PMSLEEP_SLEEP_MIN_TIME)"-"STRINGIFY(PMSLEEP_SLEEP_MAX_TIME)" us";
@@ -28,17 +30,18 @@ static void wifi_suspended_timer_cb(int arg);
 
 /*  INTERNAL FUNCTIONS  */
 
-#include "swTimer/swTimer.h"
 static void suspend_all_timers(void){
-#ifdef ENABLE_TIMER_SUSPEND
-  swtmr_suspend(NULL);
+#ifdef TIMER_SUSPEND_ENABLE
+  extern void swtmr_suspend_timers();
+  swtmr_suspend_timers();
 #endif
   return;
 }
 
 static void resume_all_timers(void){
-#ifdef ENABLE_TIMER_SUSPEND
-  swtmr_resume(NULL);
+#ifdef TIMER_SUSPEND_ENABLE
+  extern void swtmr_resume_timers();
+  swtmr_resume_timers();
 #endif
   return;
 }
@@ -49,7 +52,7 @@ static void null_mode_check_timer_cb(void* arg){
     if(current_config.sleep_mode == LIGHT_SLEEP_T){
       if((READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT<<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();
         //Ensure UART 0/1 TX FIFO is clear
         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){
         PMSLEEP_DBG("wifi_fpm_do_sleep success, starting wifi_suspend_test timer");
         os_timer_disarm(&wifi_suspended_test_timer);
         os_timer_setfn(&wifi_suspended_test_timer, (os_timer_func_t*)wifi_suspended_timer_cb, NULL);
+          //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);
       }
       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){
         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;
   }
 }
@@ -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){
   lua_Integer Linteger_tmp = 0;
 
-  lua_getfield(L, table_idx, "duration");
-  if( !lua_isnil(L, -1) ){  /* found? */
-    if( lua_isnumber(L, -1) ){
-      lua_Integer Linteger=luaL_checkinteger(L, -1);
-      luaL_argcheck(L,(((Linteger >= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) ||
-          (Linteger == 0)), table_idx, PMSLEEP_DURATION_ERR_STR);
-      cfg->sleep_duration = (uint32)Linteger; // Get suspend duration
+  if( cfg->sleep_mode == MODEM_SLEEP_T ){ //WiFi suspend
+    lua_getfield(L, table_idx, "duration");
+    if( !lua_isnil(L, -1) ){  /* found? */
+      if( lua_isnumber(L, -1) ){
+        lua_Integer Linteger=luaL_checkinteger(L, -1);
+        luaL_argcheck(L,(((Linteger >= PMSLEEP_SLEEP_MIN_TIME) && (Linteger <= PMSLEEP_SLEEP_MAX_TIME)) ||
+            (Linteger == 0)), table_idx, PMSLEEP_DURATION_ERR_STR);
+        cfg->sleep_duration = (uint32)Linteger; // Get suspend duration
+      }
+      else{
+        return luaL_argerror( L, table_idx, "duration: must be number" );
+      }
     }
     else{
-      return luaL_argerror( L, table_idx, "duration: must be number" );
+      return luaL_argerror( L, table_idx, PMSLEEP_DURATION_ERR_STR );
     }
-  }
-  else{
-    return luaL_argerror( L, table_idx, PMSLEEP_DURATION_ERR_STR );
-  }
-  lua_pop(L, 1);
+    lua_pop(L, 1);
 
-  if( cfg->sleep_mode == MODEM_SLEEP_T ){ //WiFi suspend
     lua_getfield(L, table_idx, "suspend_cb");
     if( !lua_isnil(L, -1) ){  /* found? */
       if( lua_isfunction(L, -1) ){
@@ -204,7 +209,7 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg,
     lua_pop(L, 1);
   }
   else if (cfg->sleep_mode == LIGHT_SLEEP_T){ //CPU suspend
-#ifdef ENABLE_TIMER_SUSPEND
+#ifdef TIMER_SUSPEND_ENABLE
     lua_getfield(L, table_idx, "wake_pin");
     if( !lua_isnil(L, -1) ){  /* found? */
       if( lua_isnumber(L, -1) ){
@@ -216,9 +221,11 @@ int pmSleep_parse_table_lua( lua_State* L, int table_idx, pmSleep_param_t *cfg,
         return luaL_argerror( L, table_idx, "wake_pin: must be number" );
       }
     }
-    else if(cfg->sleep_duration == 0){
-      return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" );
-    }
+    else{
+      return luaL_argerror( L, table_idx, "wake_pin: must specify pin" );
+//    else if(cfg->sleep_duration == 0){
+//      return luaL_argerror( L, table_idx, "wake_pin: must specify pin if sleep duration is indefinite" );
+  }
     lua_pop(L, 1);
 
     lua_getfield(L, table_idx, "int_type");
@@ -300,7 +307,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
   PMSLEEP_DBG("START");
 
   lua_State* L = lua_getstate();
-#ifndef ENABLE_TIMER_SUSPEND
+#ifndef TIMER_SUSPEND_ENABLE
   if(cfg->sleep_mode == LIGHT_SLEEP_T){
     luaL_error(L, "timer suspend API is disabled, light sleep unavailable");
     return;
@@ -336,7 +343,7 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
     wifi_fpm_open(); // Enable force sleep API
 
     if (cfg->sleep_mode == LIGHT_SLEEP_T){
-#ifdef ENABLE_TIMER_SUSPEND
+#ifdef TIMER_SUSPEND_ENABLE
       if(platform_gpio_exists(cfg->wake_pin) && cfg->wake_pin > 0){
         PMSLEEP_DBG("Wake-up pin is %d\t interrupt type is %d", cfg->wake_pin, cfg->int_type);
 
@@ -366,10 +373,11 @@ void pmSleep_suspend(pmSleep_param_t *cfg){
     c_memcpy(&current_config, cfg, sizeof(pmSleep_param_t));
     PMSLEEP_DBG("sleep duration is %d", current_config.sleep_duration);
 
-    //this timer intentionally bypasses the swtimer timer registration process
-    ets_timer_disarm(&null_mode_check_timer);
-    ets_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false);
-    ets_timer_arm_new(&null_mode_check_timer, 1, 1, 1);
+    os_timer_disarm(&null_mode_check_timer);
+    os_timer_setfn(&null_mode_check_timer, null_mode_check_timer_cb, false);
+      //The function null_mode_check_timer_cb checks that the esp8266 has successfully changed the opmode to NULL_MODE prior to entering LIGHT_SLEEP
+      //This callback doesn't need to be registered with SWTIMER_REG_CB since the timer will have terminated before entering LIGHT_SLEEP
+    os_timer_arm(&null_mode_check_timer, 1, 1);
   }
   else{
     PMSLEEP_ERR("opmode change fail");

+ 545 - 0
app/pm/swtimer.c

@@ -0,0 +1,545 @@
+/* swTimer.c SDK timer suspend API
+ *
+ * SDK software timer API info:
+ *
+ * The SDK software timer uses a linked list called `os_timer_t* timer_list` to keep track of
+ * all currently armed timers.
+ *
+ * The SDK software timer API executes in a task. The priority of this task in relation to the
+ * application level tasks is unknown (at time of writing).
+ *
+ *
+ * To determine when a timer's callback should be executed, the respective timer's `timer_expire`
+ *  variable is compared to the hardware counter(FRC2), then, if the timer's `timer_expire` is
+ *  less than the current FRC2 count, the timer's callback is fired.
+ *
+ * The timers in this list are organized in an ascending order starting with the timer
+ * with the lowest timer_expire.
+ *
+ * When a timer expires that has a timer_period greater than 0, timer_expire is changed to
+ * current FRC2 + timer_period, then the timer is inserted back in to the list in the correct position.
+ *
+ * when using millisecond(default) timers, FRC2 resolution is 312.5 ticks per millisecond.
+ *
+ *
+ * TIMER SUSPEND API INFO:
+ *
+ * Timer suspension is achieved by first finding any non-SDK timers by comparing the timer function callback pointer
+ * of each timer in "timer_list" to a list of registered timer callback pointers stored in the Lua registry.
+ * If a timer with a corresponding registered callback pointer is found, the timer's timer_expire field is is compared
+ * to the current FRC2 count and the difference is saved along with the other timer parameters to temporary variables.
+ * The timer is then disarmed and the parameters are copied back, the timer pointer is then
+ * added to a separate linked list of which the head pointer is stored as a lightuserdata in the lua registry.
+ *
+ * Resuming the timers is achieved by first retrieving the lightuserdata holding the suspended timer list head pointer.
+ * Then, starting with the beginning of the list the current FRC2 count is added back to the timer's timer_expire, then
+ * the timer is manually added back to "timer_list" in an ascending order.
+ * Once there are no more suspended timers, the function returns
+ *
+ *
+ */#include "module.h"
+#include "lauxlib.h"
+#include "platform.h"
+
+#include "user_interface.h"
+#include "user_modules.h"
+
+#include "c_string.h"
+#include "c_stdlib.h"
+#include "ctype.h"
+
+#include "c_types.h"
+
+//#define SWTMR_DEBUG
+#if !defined(SWTMR_DBG) && defined(LUA_USE_MODULES_SWTMR_DBG)
+ #define SWTMR_DEBUG
+#endif
+
+//this section specifies which lua registry to use. LUA_GLOBALSINDEX or LUA_REGISTRYINDEX
+#ifdef SWTMR_DEBUG
+#define SWTMR_DBG(fmt, ...) c_printf("\n SWTMR_DBG(%s): "fmt"\n", __FUNCTION__, ##__VA_ARGS__)
+#define L_REGISTRY LUA_GLOBALSINDEX
+#define CB_LIST_STR "timer_cb_ptrs"
+#define SUSP_LIST_STR "suspended_tmr_LL_head"
+#else
+#define SWTMR_DBG(...)
+#define L_REGISTRY LUA_REGISTRYINDEX
+#define CB_LIST_STR "cb"
+#define SUSP_LIST_STR "st"
+#endif
+
+
+typedef struct tmr_cb_queue{
+  os_timer_func_t *tmr_cb_ptr;
+  uint8 suspend_policy;
+  struct tmr_cb_queue * next;
+}tmr_cb_queue_t;
+
+typedef struct cb_registry_item{
+  os_timer_func_t *tmr_cb_ptr;
+  uint8 suspend_policy;
+}cb_registry_item_t;
+
+
+/*  Internal variables  */
+static tmr_cb_queue_t* register_queue = NULL;
+static task_handle_t cb_register_task_id = NULL; //variable to hold task id for task handler(process_cb_register_queue)
+
+/*  Function declarations */
+//void swtmr_cb_register(void* timer_cb_ptr, uint8 resume_policy);
+static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy);
+static void process_cb_register_queue(task_param_t param, uint8 priority);
+
+
+#ifdef SWTMR_DEBUG
+#define push_swtmr_registry_key(L) lua_pushstring(L, "SWTMR_registry_key")
+#else
+#define push_swtmr_registry_key(L) lua_pushlightuserdata(L, &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(int i = 0; i < registered_cb_qty; i++){
+      if(timer_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){
+
+        //current timer will be suspended, next timer's pointer will be needed to continue processing timer_list
+        next_timer = timer_ptr->timer_next;
+
+        //store timer parameters temporarily so the timer can be disarmed
+        if(timer_ptr->timer_expire < frc2_count)
+          expire_temp = 2; //  16 us in ticks (1 tick = ~3.2 us) (arbitrarily chosen value)
+        else
+          expire_temp = timer_ptr->timer_expire - frc2_count;
+        period_temp = timer_ptr->timer_period;
+        arg_temp = timer_ptr->timer_arg;
+
+        if(timer_ptr->timer_period == 0 && cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){
+          SWTMR_DBG("Warning: suspend_policy(RESTART) is not compatible with single-shot timer(%p), changing suspend_policy to (RESUME)", timer_ptr);
+          cb_reg_array[i]->suspend_policy = SWTIMER_RESUME;
+        }
+
+        //remove the timer from timer_list so we don't have to.
+        os_timer_disarm(timer_ptr); 
+
+        timer_ptr->timer_next = NULL;
+
+        //this section determines timer behavior on resume
+        if(cb_reg_array[i]->suspend_policy == SWTIMER_DROP){
+          SWTMR_DBG("timer(%p) was disarmed and will not be resumed", timer_ptr);
+        }
+        else if(cb_reg_array[i]->suspend_policy == SWTIMER_IMMEDIATE){
+          timer_ptr->timer_expire = 1;
+          SWTMR_DBG("timer(%p) will fire immediately on resume", timer_ptr);
+        }
+        else if(cb_reg_array[i]->suspend_policy == SWTIMER_RESTART){
+          timer_ptr->timer_expire = period_temp;
+          SWTMR_DBG("timer(%p) will be restarted on resume", timer_ptr);
+        }
+        else{
+          timer_ptr->timer_expire = expire_temp;
+          SWTMR_DBG("timer(%p) will be resumed with remaining time", timer_ptr);
+        }
+
+        if(cb_reg_array[i]->suspend_policy != SWTIMER_DROP){
+          timer_ptr->timer_period = period_temp;
+          timer_ptr->timer_func = cb_reg_array[i]->tmr_cb_ptr;
+          timer_ptr->timer_arg = arg_temp;
+
+          //add timer to suspended_timer_list
+          if(suspended_timer_list_head == NULL){
+            suspended_timer_list_head = timer_ptr;
+            suspended_timer_list_tail = timer_ptr;
+          }
+          else{
+            suspended_timer_list_tail->timer_next = timer_ptr;
+            suspended_timer_list_tail = timer_ptr;
+          }
+        }
+      }
+    }
+
+    //if timer was suspended, timer_ptr->timer_next is invalid, use next_timer instead.
+    if(next_timer != (os_timer_t*)0xffffffff){
+      timer_ptr = next_timer;
+    }
+    else{
+      timer_ptr = timer_ptr->timer_next;
+    }
+  }
+
+  //tmr_cb_ptr_array is no longer needed.
+  c_free(cb_reg_array);
+
+  //add suspended_timer_list pointer to swtimer table.
+  lua_pushstring(L, SUSP_LIST_STR);
+  lua_pushlightuserdata(L, suspended_timer_list_head);
+  lua_rawset(L, -3);
+
+  //pop swtimer table from stack
+  lua_pop(L, 1);
+  return;
+}
+
+void swtmr_resume_timers(){
+  lua_State* L = lua_getstate();
+  
+  //get swtimer table
+  push_swtmr_registry_key(L);
+  lua_rawget(L, L_REGISTRY);
+
+  //get suspended_timer_list lightuserdata
+  lua_pushstring(L, SUSP_LIST_STR);
+  lua_rawget(L, -2);
+  
+  //check for existence of swtimer table and the suspended_timer_list pointer userdata, return if not found
+  if(!lua_istable(L, -2) || !lua_isuserdata(L, -1)){
+    // not necessarily an error maybe there are legitimately no timers to resume
+    lua_pop(L, 2);
+    return;
+  }
+
+  os_timer_t* suspended_timer_list_ptr = lua_touserdata(L, -1);
+  lua_pop(L, 1); //pop suspended timer list userdata from stack
+
+  //since timers will be resumed, the suspended_timer_list lightuserdata can be cleared from swtimer table
+  lua_pushstring(L, SUSP_LIST_STR);
+  lua_pushnil(L);
+  lua_rawset(L, -3);
+  
+
+  lua_pop(L, 1); //pop swtimer table from stack
+
+  volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
+
+  //this section does the actual resuming of the suspended timer(s)
+  while(suspended_timer_list_ptr != NULL){
+    os_timer_t* timer_list_ptr = timer_list;
+
+    //the pointer to next suspended timer must be saved, the current suspended timer will be removed from the list
+    os_timer_t* next_suspended_timer_ptr = suspended_timer_list_ptr->timer_next;
+
+    suspended_timer_list_ptr->timer_expire += frc2_count;
+
+    //traverse timer_list to determine where to insert suspended timer
+    while(timer_list_ptr != NULL){
+      if(suspended_timer_list_ptr->timer_expire > timer_list_ptr->timer_expire){
+        if(timer_list_ptr->timer_next != NULL){
+          //current timer is not at tail of timer_list
+          if(suspended_timer_list_ptr->timer_expire < timer_list_ptr->timer_next->timer_expire){
+            //insert suspended timer between current timer and next timer
+            suspended_timer_list_ptr->timer_next = timer_list_ptr->timer_next;
+            timer_list_ptr->timer_next = suspended_timer_list_ptr;
+            break; //timer resumed exit while loop
+          }
+          else{
+            //suspended timer expire is larger than next timer
+          }
+        }
+        else{
+          //current timer is at tail of timer_list and suspended timer expire is greater then current timer
+          //append timer to end of timer_list
+          timer_list_ptr->timer_next = suspended_timer_list_ptr;
+          suspended_timer_list_ptr->timer_next = NULL;
+          break; //timer resumed exit while loop
+        }
+      }
+      else if(timer_list_ptr == timer_list){
+        //insert timer at head of list
+        suspended_timer_list_ptr->timer_next = timer_list_ptr;
+        timer_list = timer_list_ptr = suspended_timer_list_ptr;
+        break; //timer resumed exit while loop
+      }
+      //suspended timer expire is larger than next timer
+      //timer not resumed, next timer in timer_list
+      timer_list_ptr = timer_list_ptr->timer_next;
+    }
+    //timer was resumed, next suspended timer
+    suspended_timer_list_ptr = next_suspended_timer_ptr;
+  }
+  return;
+}
+
+//this function registers a timer callback pointer in a lua table
+void swtmr_cb_register(void* timer_cb_ptr, uint8 suspend_policy){
+  lua_State* L = lua_getstate();
+  if(!L){
+    //Lua has not started yet, therefore L_REGISTRY is not available.
+    //add timer cb to queue for later processing after Lua has started
+    add_to_reg_queue(timer_cb_ptr, suspend_policy);
+    return;
+  }
+  if(timer_cb_ptr){
+    size_t cb_list_last_idx = 0;
+
+    push_swtmr_registry_key(L);
+    lua_rawget(L, L_REGISTRY);
+
+    if(!lua_istable(L, -1)){
+      //swtmr does not exist, create and add to registry
+      lua_pop(L, 1);
+      lua_newtable(L);//push new table for swtmr.timer_cb_list
+      // add swtimer table to L_REGISTRY
+      push_swtmr_registry_key(L);
+      lua_pushvalue(L, -2);
+      lua_rawset(L, L_REGISTRY);
+    }
+
+    lua_pushstring(L, CB_LIST_STR);
+    lua_rawget(L, -2);
+
+    if(lua_istable(L, -1)){
+      //cb_list exists, get length of list
+      cb_list_last_idx = lua_objlen(L, -1);
+    }
+    else{
+      //cb_list does not exist in swtmr, create and add to swtmr
+      lua_pop(L, 1);// pop nil value from stack
+      lua_newtable(L);//create new table for swtmr.timer_cb_list
+      lua_pushstring(L, CB_LIST_STR); //push name for the new table onto the stack
+      lua_pushvalue(L, -2); //push table to top of stack
+      lua_rawset(L, -4); //pop table and name from stack and register in swtmr
+    }
+
+    //append new timer cb ptr to table
+    lua_pushnumber(L, cb_list_last_idx+1);
+    cb_registry_item_t* reg_item = lua_newuserdata(L, sizeof(cb_registry_item_t));
+    reg_item->tmr_cb_ptr = timer_cb_ptr;
+    reg_item->suspend_policy = suspend_policy;
+    lua_rawset(L, -3);
+
+    //clear items pushed onto stack by this function
+    lua_pop(L, 2);
+  }
+  return;
+}
+
+//this function adds the timer cb ptr to a queue for later registration after lua has started
+static void add_to_reg_queue(void* timer_cb_ptr, uint8 suspend_policy){
+  if(!timer_cb_ptr)
+    return;
+  tmr_cb_queue_t* queue_temp = c_zalloc(sizeof(tmr_cb_queue_t));
+  if(!queue_temp){
+    //it's boot time currently and we're already out of memory, something is very wrong...
+    c_printf("\n\t%s:out of memory, system halted!\n", __FUNCTION__);
+    while(1)
+      system_soft_wdt_feed();
+  }
+  queue_temp->tmr_cb_ptr = timer_cb_ptr;
+  queue_temp->suspend_policy = suspend_policy;
+  queue_temp->next = NULL;
+
+  if(register_queue == NULL){
+    register_queue = queue_temp;
+  }
+  else{
+    tmr_cb_queue_t* queue_ptr = register_queue;
+    while(queue_ptr->next != NULL){
+      queue_ptr = queue_ptr->next;
+    }
+    queue_ptr->next = queue_temp;
+  }
+  if(!cb_register_task_id){
+  cb_register_task_id = task_get_id(process_cb_register_queue);//get task id from task interface
+  task_post_low(cb_register_task_id, false); //post task to process next item in queue
+  }
+  return;
+}
+
+static void process_cb_register_queue(task_param_t param, uint8 priority)
+{
+  if(!lua_getstate()){
+    SWTMR_DBG("L== NULL, Lua not yet started! posting task");
+    task_post_low(cb_register_task_id, false); //post task to process next item in queue
+    return;
+  }
+  while(register_queue != NULL){
+    tmr_cb_queue_t* register_queue_ptr = register_queue;
+    void* cb_ptr_tmp = register_queue_ptr->tmr_cb_ptr;
+    swtmr_cb_register(cb_ptr_tmp, register_queue_ptr->suspend_policy);
+    register_queue = register_queue->next;
+    c_free(register_queue_ptr);
+  }
+  return;
+}
+
+#ifdef SWTMR_DEBUG
+int print_timer_list(lua_State* L){
+   push_swtmr_registry_key(L);
+   lua_rawget(L, L_REGISTRY);
+   lua_pushstring(L, CB_LIST_STR);
+   lua_rawget(L, -2);
+   if(!lua_istable(L, -2) || !lua_istable(L, -1)){
+     lua_pop(L, 2);
+     return 0;
+   }
+   os_timer_t* suspended_timer_list_head = NULL;
+   os_timer_t* suspended_timer_list_tail = NULL;
+   lua_pushstring(L, SUSP_LIST_STR);
+   lua_rawget(L, -3);
+   if(lua_isuserdata(L, -1)){
+     suspended_timer_list_head = suspended_timer_list_tail = lua_touserdata(L, -1);
+     while(suspended_timer_list_tail->timer_next != NULL){
+       suspended_timer_list_tail = suspended_timer_list_tail->timer_next;
+     }
+   }
+   lua_pop(L, 1);
+   size_t registered_cb_qty = lua_objlen(L, -1);
+   cb_registry_item_t** cb_reg_array = c_zalloc(sizeof(cb_registry_item_t*)*registered_cb_qty);
+   if(!cb_reg_array){
+     luaL_error(L, "%s: unable to suspend timers, out of memory!", __func__);
+     return 0;
+   }
+   uint8 index = 0;
+   lua_pushnil(L);
+   while(lua_next(L, -2) != 0){
+     if(lua_isuserdata(L, -1)){
+       cb_reg_array[index] = lua_touserdata(L, -1);
+     }
+     lua_pop(L, 1);
+     index++;
+   }
+   lua_pop(L, 1);
+
+
+  os_timer_t* timer_list_ptr = timer_list;
+  c_printf("\n\tCurrent FRC2: %u\n", RTC_REG_READ(FRC2_COUNT_ADDRESS));
+  c_printf("\ttimer_list:\n");
+  while(timer_list_ptr != NULL){
+    bool registered_flag = FALSE;
+    for(int i=0; i < registered_cb_qty; i++){
+      if(timer_list_ptr->timer_func == cb_reg_array[i]->tmr_cb_ptr){
+        registered_flag = TRUE;
+        break;
+      }
+    }
+    c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\t%s\n",
+        timer_list_ptr, timer_list_ptr->timer_func, timer_list_ptr->timer_expire, timer_list_ptr->timer_period, timer_list_ptr->timer_next, registered_flag ? "Registered" : "");
+    timer_list_ptr = timer_list_ptr->timer_next;
+  }
+
+  c_free(cb_reg_array);
+  lua_pop(L, 1);
+
+  return 0;
+}
+
+int print_susp_timer_list(lua_State* L){
+  push_swtmr_registry_key(L);
+  lua_rawget(L, L_REGISTRY);
+
+  if(!lua_istable(L, -1)){
+    return luaL_error(L, "swtmr table not found!");
+  }
+
+  lua_pushstring(L, SUSP_LIST_STR);
+  lua_rawget(L, -2);
+
+  if(!lua_isuserdata(L, -1)){
+    return luaL_error(L, "swtmr.suspended_list userdata not found!");
+  }
+
+  os_timer_t* susp_timer_list_ptr = lua_touserdata(L, -1);
+  c_printf("\n\tsuspended_timer_list:\n");
+  while(susp_timer_list_ptr != NULL){
+    c_printf("\tptr:%p\tcb:%p\texpire:%8u\tperiod:%8u\tnext:%p\n",susp_timer_list_ptr, susp_timer_list_ptr->timer_func, susp_timer_list_ptr->timer_expire, susp_timer_list_ptr->timer_period, susp_timer_list_ptr->timer_next);
+    susp_timer_list_ptr = susp_timer_list_ptr->timer_next;
+  }
+  return 0;
+}
+
+int suspend_timers_lua(lua_State* L){
+  swtmr_suspend_timers();
+  return 0;
+}
+
+int resume_timers_lua(lua_State* L){
+  swtmr_resume_timers();
+  return 0;
+}
+
+static const LUA_REG_TYPE test_swtimer_debug_map[] = {
+    { LSTRKEY( "timer_list" ),   LFUNCVAL( print_timer_list ) },
+    { LSTRKEY( "susp_timer_list" ),   LFUNCVAL( print_susp_timer_list ) },
+    { LSTRKEY( "suspend" ),      LFUNCVAL( suspend_timers_lua ) },
+    { LSTRKEY( "resume" ),      LFUNCVAL( resume_timers_lua ) },
+    { LNILKEY, LNILVAL }
+};
+
+NODEMCU_MODULE(SWTMR_DBG, "SWTMR_DBG", test_swtimer_debug_map, NULL);
+
+#endif
+

+ 8 - 0
app/smart/smart.c

@@ -3,6 +3,7 @@
 #include "c_string.h"
 #include "user_interface.h"
 #include "smart.h"
+#include "pm/swtimer.h"
 
 #define ADDR_MAP_NUM 10
 
@@ -500,6 +501,9 @@ void smart_end(){
 
       os_timer_disarm(&smart_timer);
       os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)1);
+      SWTIMER_REG_CB(station_check_connect, SWTIMER_RESUME);
+        //the function station_check_connect continues the Smart config process and fires the developers callback upon successful connection to the access point.
+        //If this function manages to get suspended, I think it would be fine to resume the timer.
       os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0);   // no repeat
     }
   }
@@ -672,6 +676,9 @@ void smart_begin(int chnl, smart_succeed s, void *arg){
   wifi_set_promiscuous_rx_cb(detect);
   os_timer_disarm(&smart_timer);
   os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL);
+  SWTIMER_REG_CB(smart_next_channel, SWTIMER_RESUME);
+    //smart_next_channel switches the wifi channel
+    //I don't see a problem with resuming this timer
   os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0);   // no repeat
 
   if(s){
@@ -717,5 +724,6 @@ void station_check_connect(bool smart){
   }
   os_timer_disarm(&smart_timer);
   os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)(int)smart);
+    //this function was already registered in the function smart_end.
   os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0);   // no repeat
 }

+ 0 - 52
app/swTimer/Makefile

@@ -1,52 +0,0 @@
-
-#############################################################
-# Required variables for each makefile
-# Discard this section from all parent makefiles
-# Expected variables (with automatic defaults):
-#   CSRCS (all "C" files in the dir)
-#   SUBDIRS (all subdirs with a Makefile)
-#   GEN_LIBS - list of libs to be generated ()
-#   GEN_IMAGES - list of images to be generated ()
-#   COMPONENTS_xxx - a list of libs/objs in the form
-#     subdir/lib to be extracted and rolled up into
-#     a generated lib/image xxx.a ()
-#
-ifndef PDIR
-GEN_LIBS = libswtimer.a
-endif
-
-STD_CFLAGS=-std=gnu11 -Wimplicit
-
-#############################################################
-# Configuration i.e. compile options etc.
-# Target specific stuff (defines etc.) goes in here!
-# Generally values applying to a tree are captured in the
-#   makefile at its root level - these are then overridden
-#   for a subtree within the makefile rooted therein
-#
-#DEFINES += 
-
-#############################################################
-# Recursion Magic - Don't touch this!!
-#
-# Each subtree potentially has an include directory
-#   corresponding to the common APIs applicable to modules
-#   rooted at that subtree. Accordingly, the INCLUDE PATH
-#   of a module can only contain the include directories up
-#   its parent path, and not its siblings
-#
-# Required for each makefile to inherit from the parent
-#
-
-INCLUDES := $(INCLUDES) -I $(PDIR)include
-INCLUDES += -I ./
-INCLUDES += -I ./include
-INCLUDES += -I ../include
-INCLUDES += -I ../../include
-INCLUDES += -I ../lua
-INCLUDES += -I ../platform
-INCLUDES += -I ../libc
-
-PDIR := ../$(PDIR)
-sinclude $(PDIR)Makefile
-

+ 0 - 632
app/swTimer/swTimer.c

@@ -1,632 +0,0 @@
-/* swTimer.c SDK timer suspend API
- *
- * SDK software timer API info:
- *
- * The SDK software timer uses a linked list called `os_timer_t* timer_list` to keep track of
- * all currently armed timers.
- *
- * The SDK software timer API executes in a task. The priority of this task in relation to the
- * application level tasks is unknown (at time of writing).
- *
- *
- * To determine when a timer's callback should be executed, the respective timer's `timer_expire`
- *  variable is compared to the hardware counter(FRC2), then, if the timer's `timer_expire` is
- *  less than the current FRC2 count, the timer's callback is fired.
- *
- * The timers in this list are organized in an ascending order starting with the timer
- * with the lowest timer_expire.
- *
- * When a timer expires that has a timer_period greater than 0, timer_expire is changed to
- * current FRC2 + timer_period, then the timer is inserted back in to the list in the correct position.
- *
- * when using millisecond(default) timers, FRC2 resolution is 312.5 ticks per millisecond.
- *
- *
- * TIMER SUSPEND API:
- *
- *  Timer registry:
- * void sw_timer_register(void* timer_ptr);
- * - Adds timers to the timer registry by adding it to a queue that is later
- *   processed by timer_register_task that performs the registry maintenance
- *
- * void sw_timer_unregister(void* timer_ptr);
- * - Removes timers from the timer registry by adding it to a queue that is later
- *   processed by timer_unregister_task that performs the registry maintenance
- *
- *
- * int sw_timer_suspend(os_timer_t* timer_ptr);
- * - Suspend a single active timer or suspend all active timers.
- * - if no timer pointer is provided, timer_ptr == NULL, then all currently active timers will be suspended.
- *
- * int sw_timer_resume(os_timer_t* timer_ptr);
- * - Resume a single suspended timer or resume all suspended timers.
- * - if no timer pointer is provided, timer_ptr == NULL, then all currently suspended timers will be resumed.
- *
- *
- *
- */
-#include "swTimer/swTimer.h"
-#include "c_stdio.h"
-#include "misc/dynarr.h"
-#include "task/task.h"
-
-#ifdef ENABLE_TIMER_SUSPEND
-
-/*      Settings      */
-#define TIMER_REGISTRY_INITIAL_SIZE 10
-#ifdef USE_SWTMR_ERROR_STRINGS
-static const char* SWTMR_ERROR_STRINGS[]={
-    [SWTMR_MALLOC_FAIL] = "Out of memory!",
-    [SWTMR_TIMER_NOT_ARMED] = "Timer is not armed",
-//    [SWTMR_NULL_PTR] = "A NULL pointer was passed to timer suspend api",
-    [SWTMR_REGISTRY_NO_REGISTERED_TIMERS] = "No timers in registry",
-//    [SWTMR_SUSPEND_ARRAY_INITIALIZATION_FAILED] = "Suspend array init fail",
-//    [SWTMR_SUSPEND_ARRAY_ADD_FAILED] = "Unable to add suspended timer to array",
-//    [SWTMR_SUSPEND_ARRAY_REMOVE_FAILED] = "Unable to remove suspended timer from array",
-    [SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED] = "Already suspended",
-    [SWTMR_SUSPEND_TIMER_ALREADY_REARMED] = "Already been re-armed",
-    [SWTMR_SUSPEND_NO_SUSPENDED_TIMERS] = "No suspended timers",
-    [SWTMR_SUSPEND_TIMER_NOT_SUSPENDED] = "Not suspended",
-
-};
-#endif
-
-/*     Private Function Declarations      */
-static inline bool timer_armed_check(os_timer_t* timer_ptr);
-static inline int timer_do_suspend(os_timer_t* timer_ptr);
-static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr);
-static void timer_register_task(task_param_t param, uint8 priority);
-static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr);
-static inline void timer_registry_remove_unarmed(void);
-static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr);
-static void timer_unregister_task(task_param_t param, uint8 priority);
-
-/*      Private Variable Definitions      */
-  static task_handle_t timer_reg_task_id = false;
-  static task_handle_t timer_unreg_task_id = false;
-
-  static dynarr_t timer_registry = {0};
-  static dynarr_t suspended_timers = {0};
-
-  typedef struct registry_queue{
-    struct registry_queue* next;
-    os_timer_t* timer_ptr;
-  }registry_queue_t;
-
-  static registry_queue_t* register_queue = NULL;
-  static registry_queue_t* unregister_queue = NULL;
-
-/*      Private Function Definitions     */
-
-//NOTE: Interrupts are temporarily blocked during the execution of this function
-static inline bool timer_armed_check(os_timer_t* timer_ptr){
-  bool retval = FALSE;
-
-  // we are messing around with the SDK timer structure here, may not be necessary, better safe than sorry though.
-  ETS_INTR_LOCK();
-
-  os_timer_t* timer_list_ptr = timer_list; //get head node pointer of timer_list
-
-  //if present find timer_ptr in timer_list rand return result
-  while(timer_list_ptr != NULL){
-    if(timer_list_ptr == timer_ptr){
-      retval = TRUE;
-      break;
-    }
-    timer_list_ptr = timer_list_ptr->timer_next;
-  }
-
-  //we are done with timer_list, it is now safe to unlock interrupts
-  ETS_INTR_UNLOCK();
-
-  //return value
-  return retval;
-}
-
-static inline int timer_do_suspend(os_timer_t* timer_ptr){
-  if(timer_ptr == NULL){
-    SWTMR_ERR("timer_ptr is invalid");
-    return SWTMR_FAIL;
-  }
-
-  volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
-
-  if(timer_armed_check(timer_ptr) == FALSE){
-    return SWTMR_TIMER_NOT_ARMED;
-  }
-
-  os_timer_t** suspended_timer_ptr = timer_suspended_check(timer_ptr);
-
-  uint32 expire_temp = 0;
-  uint32 period_temp = timer_ptr->timer_period;
-
-  if(timer_ptr->timer_expire < frc2_count){
-    expire_temp = 5; //  16 us in ticks (1 tick = ~3.2 us) (arbitrarily chosen value)
-  }
-  else{
-    expire_temp = timer_ptr->timer_expire - frc2_count;
-  }
-
-  ets_timer_disarm(timer_ptr);
-  timer_unregister_task((task_param_t)timer_ptr, false);
-
-  timer_ptr->timer_expire = expire_temp;
-  timer_ptr->timer_period = period_temp;
-
-  if(suspended_timers.data_ptr == NULL){
-    if(!dynarr_init(&suspended_timers, 10, sizeof(os_timer_t*))){
-      SWTMR_ERR("Suspend array init fail");
-      return SWTMR_FAIL;
-    }
-  }
-
-  if(suspended_timer_ptr == NULL){
-//    return SWTMR_SUSPEND_TIMER_ALREADY_SUSPENDED;
-    if(!dynarr_add(&suspended_timers, &timer_ptr, sizeof(timer_ptr))){
-      SWTMR_ERR("Unable to add suspended timer to array");
-      return SWTMR_FAIL;
-    }
-  }
-
-  return SWTMR_OK;
-}
-
-//NOTE: Interrupts are temporarily blocked during the execution of this function
-static inline int timer_do_resume_single(os_timer_t** suspended_timer_ptr){
-  if(suspended_timer_ptr == NULL){
-    SWTMR_ERR("suspended_timer_ptr is invalid");
-    return SWTMR_FAIL;
-  }
-
-  os_timer_t* timer_list_ptr = NULL;
-  os_timer_t* resume_timer_ptr = *suspended_timer_ptr;
-  volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
-
-  //verify timer has not been rearmed
-  if(timer_armed_check(resume_timer_ptr) == TRUE){
-    SWTMR_DBG("Timer(%p) already rearmed, removing from array", resume_timer_ptr);
-    if(!dynarr_remove(&suspended_timers, suspended_timer_ptr)){
-      SWTMR_ERR("Failed to remove timer from suspend array");
-      return SWTMR_FAIL;
-    }
-    return SWTMR_OK;
-  }
-
-  //Prepare timer for resume
-  resume_timer_ptr->timer_expire += frc2_count;
-
-  timer_register_task((task_param_t)resume_timer_ptr, false);
-  SWTMR_DBG("Removing timer(%p) from suspend array", resume_timer_ptr);
-
-  //This section performs the actual resume of the suspended timer
-
-  // we are messing around with the SDK timer structure here, may not be necessary, better safe than sorry though.
-  ETS_INTR_LOCK();
-
-  timer_list_ptr = timer_list;
-
-  while(timer_list_ptr != NULL){
-    if(resume_timer_ptr->timer_expire > timer_list_ptr->timer_expire){
-      if(timer_list_ptr->timer_next != NULL){
-        if(resume_timer_ptr->timer_expire < timer_list_ptr->timer_next->timer_expire){
-          resume_timer_ptr->timer_next = timer_list_ptr->timer_next;
-          timer_list_ptr->timer_next = resume_timer_ptr;
-          break;
-        }
-        else{
-          //next timer in timer_list
-        }
-      }
-      else{
-        timer_list_ptr->timer_next = resume_timer_ptr;
-        resume_timer_ptr->timer_next = NULL;
-        break;
-      }
-    }
-    else if(timer_list_ptr == timer_list){
-      resume_timer_ptr->timer_next=timer_list_ptr;
-      timer_list = timer_list_ptr = resume_timer_ptr;
-      break;
-    }
-
-    timer_list_ptr = timer_list_ptr->timer_next;
-  }
-
-  //we no longer need to block interrupts
-  ETS_INTR_UNLOCK();
-
-  return SWTMR_OK;
-}
-
-static void timer_register_task(task_param_t param, uint8 priority){
-  if(timer_registry.data_ptr==NULL){
-    if(!dynarr_init(&timer_registry, TIMER_REGISTRY_INITIAL_SIZE, sizeof(os_timer_t*))){
-      SWTMR_ERR("timer registry init Fail!");
-      return;
-    }
-  }
-
-  os_timer_t* timer_ptr = NULL;
-
-  //if a timer pointer is provided, override normal queue processing behavior
-  if(param != 0){
-    timer_ptr = (os_timer_t*)param;
-  }
-  else{
-    //process an item in the register queue
-    if(register_queue == NULL){
-      /**/SWTMR_ERR("ERROR: REGISTER QUEUE EMPTY");
-      return;
-    }
-
-    registry_queue_t* queue_temp = register_queue;
-    register_queue = register_queue->next;
-
-    timer_ptr = queue_temp->timer_ptr;
-
-    c_free(queue_temp);
-
-    if(register_queue != NULL){
-      SWTMR_DBG("register_queue not empty, posting task");
-      task_post_low(timer_reg_task_id, false);
-    }
-  }
-
-  os_timer_t** suspended_tmr_ptr = timer_suspended_check(timer_ptr);
-  if(suspended_tmr_ptr != NULL){
-    if(!dynarr_remove(&suspended_timers, suspended_tmr_ptr)){
-      SWTMR_ERR("failed to remove %p from suspend registry", suspended_tmr_ptr);
-    }
-    SWTMR_DBG("removed timer from suspended timers");
-  }
-
-  if(timer_registry_check(timer_ptr) != NULL){
-    /**/SWTMR_DBG("timer(%p) found in registry, returning", timer_ptr);
-    return;
-  }
-
-  if(!dynarr_add(&timer_registry, &timer_ptr, sizeof(timer_ptr))){
-    /**/SWTMR_ERR("Registry append failed");
-    return;
-  }
-
-  return;
-}
-
-static inline os_timer_t** timer_registry_check(os_timer_t* timer_ptr){
-  if(timer_registry.data_ptr == NULL){
-    return NULL;
-  }
-  if(timer_registry.used > 0){
-
-    os_timer_t** timer_registry_array = timer_registry.data_ptr;
-
-    for(uint32 i=0; i < timer_registry.used; i++){
-      if(timer_registry_array[i] == timer_ptr){
-        /**/SWTMR_DBG("timer(%p) is registered", timer_registry_array[i]);
-        return &timer_registry_array[i];
-      }
-    }
-  }
-
-  return NULL;
-}
-
-static inline void timer_registry_remove_unarmed(void){
-  if(timer_registry.data_ptr == NULL){
-    return;
-  }
-  if(timer_registry.used > 0){
-    os_timer_t** timer_registry_array = timer_registry.data_ptr;
-    for(uint32 i=0; i < timer_registry.used; i++){
-      if(timer_armed_check(timer_registry_array[i]) == FALSE){
-        timer_unregister_task((task_param_t)timer_registry_array[i], false);
-      }
-    }
-  }
-}
-
-
-static inline os_timer_t** timer_suspended_check(os_timer_t* timer_ptr){
-  if(suspended_timers.data_ptr == NULL){
-    return NULL;
-  }
-  if(suspended_timers.used > 0){
-
-    os_timer_t** suspended_timer_array = suspended_timers.data_ptr;
-
-    for(uint32 i=0; i < suspended_timers.used; i++){
-      if(suspended_timer_array[i] == timer_ptr){
-        return &suspended_timer_array[i];
-      }
-    }
-  }
-
-  return NULL;
-}
-
-static void timer_unregister_task(task_param_t param, uint8 priority){
-  if(timer_registry.data_ptr == NULL){
-    return;
-  }
-  os_timer_t* timer_ptr = NULL;
-
-  if(param != false){
-    timer_ptr = (os_timer_t*)param;
-  }
-  else{
-
-    if(unregister_queue == NULL) {
-      SWTMR_ERR("ERROR register queue empty");
-      return;
-    }
-      registry_queue_t* queue_temp = unregister_queue;
-      timer_ptr = queue_temp->timer_ptr;
-      unregister_queue = unregister_queue->next;
-      c_free(queue_temp);
-      if(unregister_queue != NULL){
-        SWTMR_DBG("unregister_queue not empty, posting task");
-        task_post_low(timer_unreg_task_id, false);
-      }
-  }
-  if(timer_armed_check(timer_ptr) == TRUE){
-    SWTMR_DBG("%p still armed, can't remove from registry", timer_ptr);
-    return;
-  }
-
-
-  os_timer_t** registry_ptr = timer_registry_check(timer_ptr);
-  if(registry_ptr != NULL){
-    if(!dynarr_remove(&timer_registry, registry_ptr)){
-
-      /**/SWTMR_ERR("Failed to remove timer from registry");
-      /**/SWTMR_DBG("registry_ptr = %p", registry_ptr);
-      return;
-    }
-  }
-  else{
-    //timer not in registry
-  }
-  return;
-}
-
-/*      Global Function Definitions      */
-
-#if defined(SWTMR_DEBUG)
-
-void swtmr_print_registry(void){
-  volatile uint32 frc2_count = RTC_REG_READ(FRC2_COUNT_ADDRESS);
-  uint32 time_till_fire = 0;
-  uint32 time = system_get_time();
-
-  timer_registry_remove_unarmed();
-  time = system_get_time()-time;
-
-  /**/SWTMR_DBG("registry_remove_unarmed_timers() took %u us", time);
-
-  os_timer_t** timer_array = timer_registry.data_ptr;
-
-  c_printf("\n  array used(%u)/size(%u)\ttotal size(bytes)=%u\n  FRC2 COUNT %u\n",
-      timer_registry.used, timer_registry.array_size, timer_registry.array_size * timer_registry.data_size, frc2_count);
-  c_printf("\n Registered timer array contents:\n");
-  c_printf(" %-5s  %-10s  %-10s  %-13s  %-10s  %-10s  %-10s\n", "idx", "ptr", "expire", "period(tick)", "period(ms)", "fire(tick)", "fire(ms)");
-
-  for(uint32 i=0; i < timer_registry.used; i++){
-     time_till_fire = (timer_array[i]->timer_expire - frc2_count);
-     c_printf(" %-5d  %-10p  %-10d  %-13d  %-10d  %-10d  %-10d\n", i, timer_array[i], timer_array[i]->timer_expire, timer_array[i]->timer_period, (uint32)(timer_array[i]->timer_period/312.5), time_till_fire, (uint32)(time_till_fire/312.5));
-
-   }
-
-  return;
-}
-
-void swtmr_print_suspended(void){
-  os_timer_t** susp_timer_array = suspended_timers.data_ptr;
-
-  c_printf("\n array used(%u)/size(%u)\ttotal size(bytes)=%u\n",
-      suspended_timers.used, suspended_timers.array_size, suspended_timers.array_size * suspended_timers.data_size);
-  c_printf("\n Suspended timer array contents:\n");
-  c_printf(" %-5s  %-10s  %-15s  %-15s  %-14s  %-10s\n", "idx", "ptr", "time left(tick)", "time left(ms)", "period(tick)", "period(ms)");
-
-  for(uint32 i=0; i < suspended_timers.used; i++){
-    c_printf(" %-5d  %-10p  %-15d  %-15d  %-14d  %-10d\n", i, susp_timer_array[i], susp_timer_array[i]->timer_expire, (uint32)(susp_timer_array[i]->timer_expire/312.5), susp_timer_array[i]->timer_period, (uint32)(susp_timer_array[i]->timer_period/312.5));
-
-   }
-  return;
-}
-
-void swtmr_print_timer_list(void){
-  volatile uint32 frc2_count=RTC_REG_READ(FRC2_COUNT_ADDRESS);
-  os_timer_t* timer_list_ptr=NULL;
-  uint32 time_till_fire=0;
-  c_printf("\n\tcurrent FRC2 count:%u\n", frc2_count);
-  c_printf(" timer_list contents:\n");
-  c_printf(" %-10s  %-10s  %-10s  %-10s  %-10s  %-10s  %-10s\n", "ptr", "expire", "period", "func", "arg", "fire(tick)", "fire(ms)");
-
-  ETS_INTR_LOCK();
-
-  timer_list_ptr=timer_list;
-
-  while(timer_list_ptr != NULL){
-    time_till_fire=(timer_list_ptr->timer_expire - frc2_count) / 312.5;
-
-  c_printf(" %-10p  %-10u  %-10u  %-10p  %-10p  %-10u  %-10u\n",
-        timer_list_ptr, (uint32)(timer_list_ptr->timer_expire),
-        (uint32)(timer_list_ptr->timer_period ), timer_list_ptr->timer_func,
-        timer_list_ptr->timer_arg, (timer_list_ptr->timer_expire - frc2_count), time_till_fire);
-
-    timer_list_ptr=timer_list_ptr->timer_next;
-  }
-  ETS_INTR_UNLOCK();
-  c_printf(" NOTE: some timers in the above list belong to the SDK and can not be suspended\n");
-  return;
-}
-
-#endif
-
-int swtmr_suspend(os_timer_t* timer_ptr){
-  int return_value = SWTMR_OK;
-
-  if(timer_ptr != NULL){
-    // Timer pointer was provided, suspending specified timer
-
-    return_value = timer_do_suspend(timer_ptr);
-
-    if(return_value != SWTMR_OK){
-      return return_value;
-    }
-  }
-  else{
-    //timer pointer not found, suspending all timers
-
-    if(timer_registry.data_ptr == NULL){
-      return SWTMR_REGISTRY_NO_REGISTERED_TIMERS;
-    }
-
-    timer_registry_remove_unarmed();
-
-    os_timer_t** tmr_reg_arr = timer_registry.data_ptr;
-    os_timer_t* temp_ptr = tmr_reg_arr[0];
-
-    while(temp_ptr != NULL){
-      return_value = timer_do_suspend(temp_ptr);
-
-      if(return_value != SWTMR_OK){
-        return return_value;
-      }
-
-      temp_ptr = tmr_reg_arr[0];
-    }
-  }
-  return return_value;
-}
-
-int swtmr_resume(os_timer_t* timer_ptr){
-
-  if(suspended_timers.data_ptr == NULL){
-    return SWTMR_SUSPEND_NO_SUSPENDED_TIMERS;
-  }
-
-  os_timer_t** suspended_tmr_array = suspended_timers.data_ptr;
-  os_timer_t** suspended_timer_ptr = NULL;
-  int retval=SWTMR_OK;
-
-  if(timer_ptr != NULL){
-    suspended_timer_ptr = timer_suspended_check(timer_ptr);
-    if(suspended_timer_ptr == NULL){
-      //timer not suspended
-      return SWTMR_SUSPEND_TIMER_NOT_SUSPENDED;
-    }
-
-    retval = timer_do_resume_single(suspended_timer_ptr);
-    if(retval != SWTMR_OK){
-      return retval;
-    }
-  }
-  else{
-    suspended_timer_ptr = &suspended_tmr_array[0];
-
-    while(suspended_timers.used > 0){
-      retval = timer_do_resume_single(suspended_timer_ptr);
-      if(retval != SWTMR_OK){
-        SWTMR_ERR("Unable to continue resuming timers, error(%u)", retval);
-        return retval;
-      }
-      suspended_timer_ptr = &suspended_tmr_array[0];
-    }
-  }
-  return SWTMR_OK;
-}
-
-void swtmr_register(void* timer_ptr){
-  if(timer_ptr == NULL){
-    SWTMR_DBG("error: timer_ptr is NULL");
-    return;
-  }
-
-  registry_queue_t* queue_temp = c_zalloc(sizeof(registry_queue_t));
-
-  if(queue_temp == NULL){
-    SWTMR_ERR("MALLOC FAIL! req:%u, free:%u", sizeof(registry_queue_t), system_get_free_heap_size());
-    return;
-  }
-  queue_temp->timer_ptr = timer_ptr;
-
-  if(register_queue == NULL){
-    register_queue = queue_temp;
-
-    if(timer_reg_task_id == false) timer_reg_task_id = task_get_id(timer_register_task);
-    task_post_low(timer_reg_task_id, false);
-    SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr);
-  }
-  else{
-    registry_queue_t* register_queue_tail = register_queue;
-
-    while(register_queue_tail->next != NULL){
-      register_queue_tail = register_queue_tail->next;
-    }
-
-    register_queue_tail->next = queue_temp;
-    SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr);
-  }
-
-  return;
-}
-
-void swtmr_unregister(void* timer_ptr){
-  if(timer_ptr == NULL){
-    SWTMR_DBG("error: timer_ptr is NULL");
-    return;
-  }
-
-  registry_queue_t* queue_temp = c_zalloc(sizeof(registry_queue_t));
-
-  if(queue_temp == NULL){
-    SWTMR_ERR("MALLOC FAIL! req:%u, free:%u", sizeof(registry_queue_t), system_get_free_heap_size());
-    return;
-  }
-  queue_temp->timer_ptr=timer_ptr;
-
-  if(unregister_queue == NULL){
-    unregister_queue = queue_temp;
-    if(timer_unreg_task_id==false) timer_unreg_task_id=task_get_id(timer_unregister_task);
-    task_post_low(timer_unreg_task_id, false);
-    SWTMR_DBG("queue empty, adding timer(%p) to queue and posting task", timer_ptr);
-  }
-  else{
-    registry_queue_t* unregister_queue_tail=unregister_queue;
-    while(unregister_queue_tail->next != NULL){
-      unregister_queue_tail=unregister_queue_tail->next;
-    }
-    unregister_queue_tail->next = queue_temp;
-//    SWTMR_DBG("queue NOT empty, appending timer(%p) to queue", timer_ptr);
-  }
-
-  return;
-}
-
-const char* swtmr_errorcode2str(int error_value){
-#ifdef USE_SWTMR_ERROR_STRINGS
-  if(SWTMR_ERROR_STRINGS[error_value] == NULL){
-    SWTMR_ERR("error string %d not found", error_value);
-    return NULL;
-  }
-  else{
-    return SWTMR_ERROR_STRINGS[error_value];
-  }
-#else
-  SWTMR_ERR("error(%u)", error_value);
-  return "ERROR! for more info, use debug build";
-#endif
-
-}
-
-bool swtmr_suspended_test(os_timer_t* timer_ptr){
-  os_timer_t** test_var = timer_suspended_check(timer_ptr);
-  if(test_var == NULL){
-    return false;
-  }
-  return true;
-}
-
-#endif

+ 5 - 0
app/websocket/websocketclient.c

@@ -40,6 +40,8 @@
 #include "../crypto/digests.h"
 #include "../crypto/mech.h"
 
+#include "pm/swtimer.h"
+
 #define PROTOCOL_SECURE "wss://"
 #define PROTOCOL_INSECURE "ws://"
 
@@ -560,6 +562,7 @@ static void ws_initReceiveCallback(void *arg, char *buf, unsigned short len) {
 
   os_timer_disarm(&ws->timeoutTimer);
   os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_sendPingTimeout, conn);
+  SWTIMER_REG_CB(ws_sendPingTimeout, SWTIMER_RESUME)
   os_timer_arm(&ws->timeoutTimer, WS_PING_INTERVAL_MS, true);
 
   espconn_regist_recvcb(conn, ws_receiveCallback);
@@ -706,6 +709,7 @@ static void dns_callback(const char *hostname, ip_addr_t *addr, void *arg) {
   // Set connection timeout timer
   os_timer_disarm(&ws->timeoutTimer);
   os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_connectTimeout, conn);
+  SWTIMER_REG_CB(ws_connectTimeout, SWTIMER_RESUME)
   os_timer_arm(&ws->timeoutTimer, WS_CONNECT_TIMEOUT_MS, false);
 
   if (ws->isSecure) {
@@ -867,6 +871,7 @@ void ws_close(ws_info *ws) {
 
     os_timer_disarm(&ws->timeoutTimer);
     os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_forceCloseTimeout, ws->conn);
+    SWTIMER_REG_CB(ws_forceCloseTimeout, SWTIMER_RESUME);
     os_timer_arm(&ws->timeoutTimer, WS_FORCE_CLOSE_TIMEOUT_MS, false);
   }
 }

+ 22 - 20
docs/en/modules/node.md

@@ -333,30 +333,32 @@ Put NodeMCU in light sleep mode to reduce current consumption.
 
 * NodeMCU can not enter light sleep mode if wifi is suspended.
 * All active timers will be suspended and then resumed when NodeMCU wakes from sleep. 
-* Any previously suspended timers will be resumed when NodeMCU wakes from sleep.
 
 !!! attention
     This is disabled by default. Modify `PMSLEEP_ENABLE` in `app/include/user_config.h` to enable it.
 
 #### Syntax
-`node.sleep({wake_gpio[, duration, int_type, resume_cb, preserve_mode]})`
+<!---`node.sleep({wake_pin[, duration, int_type, resume_cb, preserve_mode]})`--->
+`node.sleep({wake_pin[, int_type, resume_cb, preserve_mode]})`
 
 #### Parameters
-- `duration` Sleep duration in microseconds(μs). If a sleep duration of `0` is specified, suspension will be indefinite (Range: 0 or 50000 - 268435454 μs (0:4:28.000454))
-- `wake_pin` 1-12, pin to attach wake interrupt to. Note that pin 0(GPIO 16) does not support interrupts. 
- - If sleep duration is indefinite, `wake_pin` must be specified
- - Please refer to the [`GPIO module`](gpio.md) for more info on the pin map.
-- `int_type` type of interrupt that you would like to wake on. (Optional, Default: `node.INT_LOW`)
- - valid interrupt modes:
-  - `node.INT_UP`   Rising edge
-  - `node.INT_DOWN` Falling edge
-  - `node.INT_BOTH` Both edges
-  - `node.INT_LOW`  Low level
-  - `node.INT_HIGH` High level
-- `resume_cb` Callback to execute when WiFi wakes from suspension. (Optional)
-- `preserve_mode` preserve current WiFi mode through node sleep. (Optional, Default: true)  
- - If true, Station and StationAP modes will automatically reconnect to previously configured Access Point when NodeMCU resumes.
- - If false, discard WiFi mode and leave NodeMCU in `wifi.NULL_MODE`. WiFi mode will be restored to original mode on restart.
+<!--- timed light_sleep currently does not work, the 'duration' parameter is here as a place holder---> 
+<!--- * `duration` Sleep duration in microseconds(μs). If a sleep duration of `0` is specified, suspension will be indefinite (Range: 0 or 50000 - 268435454 μs (0:4:28.000454))--->
+
+* `wake_pin` 1-12, pin to attach wake interrupt to. Note that pin 0(GPIO 16) does not support interrupts. 
+    <!---* If sleep duration is indefinite, `wake_pin` must be specified--->
+    * Please refer to the [`GPIO module`](gpio.md) for more info on the pin map.
+* `int_type` type of interrupt that you would like to wake on. (Optional, Default: `node.INT_LOW`)
+    * valid interrupt modes:
+        * `node.INT_UP`   Rising edge
+        * `node.INT_DOWN` Falling edge
+        * `node.INT_BOTH` Both edges
+        * `node.INT_LOW`  Low level
+        * `node.INT_HIGH` High level
+* `resume_cb` Callback to execute when WiFi wakes from suspension. (Optional)
+* `preserve_mode` preserve current WiFi mode through node sleep. (Optional, Default: true)  
+    * If true, Station and StationAP modes will automatically reconnect to previously configured Access Point when NodeMCU resumes.
+    * If false, discard WiFi mode and leave NodeMCU in `wifi.NULL_MODE`. WiFi mode will be restored to original mode on restart.
 
 #### Returns
 - `nil`
@@ -379,15 +381,15 @@ Put NodeMCU in light sleep mode to reduce current consumption.
  cfg.preserve_mode=false
 
  node.sleep(cfg)
-
+```
+<!---
 --Put NodeMCU in light sleep mode for 10 seconds with resume callback
  cfg={}
  cfg.duration=10*1000*1000
  cfg.resume_cb=function() print("WiFi resume") end
 
  node.sleep(cfg)
-
-```
+--->
 
 #### See also
 - [`wifi.suspend()`](wifi.md#wifisuspend)

+ 0 - 123
docs/en/modules/tmr.md

@@ -62,11 +62,9 @@ Functions supported in timer object:
 - [`t:alarm()`](#tmralarm)
 - [`t:interval()`](#tmrinterval)
 - [`t:register()`](#tmrregister)
-- [`t:resume()`](#tmrresume)
 - [`t:start()`](#tmrstart)
 - [`t:state()`](#tmrstate)
 - [`t:stop()`](#tmrstop)
-- [`t:suspend()`](#tmrsuspend)
 - [`t:unregister()`](#tmrunregister)
 
 #### Parameters
@@ -184,61 +182,6 @@ mytimer:start()
 - [`tmr.create()`](#tmrcreate)
 - [`tmr.alarm()`](#tmralarm)
 
-## tmr.resume()
-
-Resume an individual timer.
-
-Resumes a timer that has previously been suspended with either `tmr.suspend` or `tmr.suspend_all` 
-
-#### Syntax
-`tmr.resume(id/ref)`
-
-#### Parameters
-`id/ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
-
-#### Returns
-`true` if timer was resumed successfully 
-
-#### Example
-```lua
---resume timer mytimer
-mytimer:resume()
-
---alternate metod
-tmr.resume(mytimer)
-
-```
-#### See also
-- [`tmr.suspend()`](#tmrsuspend)
-- [`tmr.suspend_all()`](#tmrsuspendall)
-- [`tmr.resume_all()`](#tmrresumeall)
-
-## tmr.resume_all()
-
-Resume all timers.
-
-Resumes all timers including those previously been suspended with either `tmr.suspend` or `tmr.suspend_all` 
-
-#### Syntax
-`tmr.resume_all()`
-
-#### Parameters
-none
-
-#### Returns
-`true` if timers were resumed successfully 
-
-#### Example
-```lua
---resume all previously suspended timers
-tmr.resume_all()
-
-```
-#### See also
-- [`tmr.suspend()`](#tmrsuspend)
-- [`tmr.suspend_all()`](#tmrsuspendall)
-- [`tmr.resume()`](#tmrresume)
-
 ## tmr.softwd()
 
 Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted.
@@ -336,72 +279,6 @@ if not mytimer:stop() then print("timer not stopped, not registered?") end
 - [`tmr.stop()`](#tmrstop)
 - [`tmr.unregister()`](#tmrunregister)
 
-## tmr.suspend()
-
-Suspend an armed timer. 
-
-!!! attention
-    This is disabled by default. Modify `ENABLE_TIMER_SUSPEND` in `app/include/user_config.h` to enable it.
-
-* Timers can be suspended at any time after they are armed.
-* If a timer is rearmed with `tmr.start` or `tmr.alarm` any matching suspended timers will be discarded.
-
-#### Syntax
-`tmr.suspend(id/ref)`
-
-#### Parameters
-`id/ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
-
-#### Returns
-`true` if timer was resumed successfully 
-
-#### Example
-```lua
---suspend timer mytimer
-mytimer:suspend()
-
---alternate metod
-tmr.suspend(mytimer)
-
-```
-#### See also
-- [`tmr.suspend_all()`](#tmrsuspendall)
-- [`tmr.resume()`](#tmrresume)
-- [`tmr.resume_all()`](#tmrresumeall)
-
-
-## tmr.suspend_all()
-
-Suspend all currently armed timers. 
-
-!!! attention
-    This is disabled by default. Modify `ENABLE_TIMER_SUSPEND` in `app/include/user_config.h` to enable it.
-    
-!!! Warning
-	This function suspends ALL active timers, including any active timers started by the NodeMCU subsystem or other modules. this may cause parts of your program to stop functioning properly. 
-	USE THIS FUNCTION AT YOUR OWN RISK!
-
-#### Syntax
-`tmr.suspend_all()`
-
-#### Parameters
-none
-
-#### Returns
-`true` if timers were suspended successfully 
-
-#### Example
-```lua
---suspend timer mytimer
-tmr.suspend_all()
-
-```
-#### See also
-- [`tmr.suspendl()`](#tmrsuspend)
-- [`tmr.resume()`](#tmrresume)
-- [`tmr.resume_all()`](#tmrresumeall)
-
-
 ## tmr.time()
 
 Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero.

+ 0 - 11
sdk-overrides/include/osapi.h

@@ -15,15 +15,4 @@ void call_user_start(void);
 
 #include_next "osapi.h"
 
-#ifdef ENABLE_TIMER_SUSPEND
-extern void swtmr_register(void* timer_ptr);
-#undef os_timer_arm
-#define os_timer_arm(timer_ptr, duration, mode) do{swtmr_register(timer_ptr); \
-  ets_timer_arm_new(timer_ptr, duration, mode, 1);}while(0);
-
-extern void swtmr_unregister(void* timer_ptr);
-#undef os_timer_disarm
-#define os_timer_disarm(timer_ptr) do{swtmr_unregister(timer_ptr); ets_timer_disarm(timer_ptr);}while(0);
-#endif
-
 #endif