Allow turning off softwd again as documented (#3327)

* Allow turning off softwd again as documented

* fix luacheck warnings

* fix outcome of review
This commit is contained in:
Gregor Hartmann 2020-11-13 12:11:29 +01:00 committed by GitHub
parent d279ba2fd9
commit 02dcc235c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 184 additions and 178 deletions

View File

@ -30,11 +30,11 @@ static const uint32 MAX_TIMEOUT=MAX_TIMEOUT_DEF;
static const char* MAX_TIMEOUT_ERR_STR = "Range: 1-"STRINGIFY(MAX_TIMEOUT_DEF); static const char* MAX_TIMEOUT_ERR_STR = "Range: 1-"STRINGIFY(MAX_TIMEOUT_DEF);
typedef struct{ typedef struct{
os_timer_t os; os_timer_t os;
sint32_t lua_ref; /* Reference to registered callback function */ sint32_t lua_ref; /* Reference to registered callback function */
sint32_t self_ref; /* Reference to UD registered slot */ sint32_t self_ref; /* Reference to UD registered slot */
uint32_t interval; uint32_t interval;
uint8_t mode; uint8_t mode;
} tmr_t; } tmr_t;
// The previous implementation extended the rtc counter to 64 bits, and then // The previous implementation extended the rtc counter to 64 bits, and then
@ -56,47 +56,47 @@ static sint32_t soft_watchdog = -1;
static os_timer_t rtc_timer; static os_timer_t rtc_timer;
static void alarm_timer_common(void* arg){ static void alarm_timer_common(void* arg){
tmr_t *tmr = (tmr_t *) arg; tmr_t *tmr = (tmr_t *) arg;
if(tmr->lua_ref > 0) { if(tmr->lua_ref > 0) {
lua_State* L = lua_getstate(); lua_State* L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
if (tmr->mode != TIMER_MODE_AUTO) { if (tmr->mode != TIMER_MODE_AUTO) {
if(tmr->mode == TIMER_MODE_SINGLE) { if(tmr->mode == TIMER_MODE_SINGLE) {
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref);
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
tmr->mode = TIMER_MODE_OFF; tmr->mode = TIMER_MODE_OFF;
} else if (tmr->mode == TIMER_MODE_SEMI) { } else if (tmr->mode == TIMER_MODE_SEMI) {
tmr->mode |= TIMER_IDLE_FLAG; tmr->mode |= TIMER_IDLE_FLAG;
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
} }
} }
luaL_pcallx(L, 1, 0); luaL_pcallx(L, 1, 0);
} }
} }
// Lua: tmr.delay( us ) // Lua: tmr.delay( us )
static int tmr_delay( lua_State* L ){ static int tmr_delay( lua_State* L ){
sint32_t us = luaL_checkinteger(L, 1); sint32_t us = luaL_checkinteger(L, 1);
luaL_argcheck(L, us>0, 1, "wrong arg range"); luaL_argcheck(L, us>0, 1, "wrong arg range");
while(us > 0){ while(us > 0){
os_delay_us(us >= 1000000 ? 1000000 : us); os_delay_us(us >= 1000000 ? 1000000 : us);
system_soft_wdt_feed (); system_soft_wdt_feed ();
us -= 1000000; us -= 1000000;
} }
return 0; return 0;
} }
// Lua: tmr.now() , return system timer in us // Lua: tmr.now() , return system timer in us
static int tmr_now(lua_State* L){ static int tmr_now(lua_State* L){
lua_pushinteger(L, (uint32_t) (0x7FFFFFFF & system_get_time())); lua_pushinteger(L, (uint32_t) (0x7FFFFFFF & system_get_time()));
return 1; return 1;
} }
// Lua: tmr.ccount() , returns CCOUNT register // Lua: tmr.ccount() , returns CCOUNT register
static int tmr_ccount(lua_State* L){ static int tmr_ccount(lua_State* L){
lua_pushinteger(L, CCOUNT_REG); lua_pushinteger(L, CCOUNT_REG);
return 1; return 1;
} }
/* /*
@ -106,69 +106,69 @@ static int tmr_ccount(lua_State* L){
// Lua: t:register( interval, mode, function ) // Lua: t:register( interval, mode, function )
static int tmr_register(lua_State* L) { static int tmr_register(lua_State* L) {
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
uint32_t interval = luaL_checkinteger(L, 2); uint32_t interval = luaL_checkinteger(L, 2);
uint8_t mode = luaL_checkinteger(L, 3); uint8_t mode = luaL_checkinteger(L, 3);
luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR); luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
luaL_argcheck(L, (mode == TIMER_MODE_SINGLE || mode == TIMER_MODE_SEMI || mode == TIMER_MODE_AUTO), 3, "Invalid mode"); luaL_argcheck(L, (mode == TIMER_MODE_SINGLE || mode == TIMER_MODE_SEMI || mode == TIMER_MODE_AUTO), 3, "Invalid mode");
luaL_argcheck(L, lua_isfunction(L, 4), 4, "Must be function"); luaL_argcheck(L, lua_isfunction(L, 4), 4, "Must be function");
//get the lua function reference //get the lua function reference
lua_pushvalue(L, 4); lua_pushvalue(L, 4);
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
os_timer_disarm(&tmr->os); os_timer_disarm(&tmr->os);
luaL_reref(L, LUA_REGISTRYINDEX, &tmr->lua_ref); luaL_reref(L, LUA_REGISTRYINDEX, &tmr->lua_ref);
tmr->mode = mode|TIMER_IDLE_FLAG; tmr->mode = mode|TIMER_IDLE_FLAG;
tmr->interval = interval; tmr->interval = interval;
os_timer_setfn(&tmr->os, alarm_timer_common, tmr); os_timer_setfn(&tmr->os, alarm_timer_common, tmr);
return 0; return 0;
} }
// Lua: t:start( [restart] ) // Lua: t:start( [restart] )
static int tmr_start(lua_State* L){ static int tmr_start(lua_State* L){
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
lua_settop(L, 2); lua_settop(L, 2);
luaL_argcheck(L, lua_isboolean(L, 2) || lua_isnil(L, 2), 2, "boolean expected"); luaL_argcheck(L, lua_isboolean(L, 2) || lua_isnil(L, 2), 2, "boolean expected");
int restart = lua_toboolean(L, 2); int restart = lua_toboolean(L, 2);
lua_settop(L, 1); /* we need to have userdata on top of the stack */ lua_settop(L, 1); /* we need to have userdata on top of the stack */
if (tmr->self_ref == LUA_NOREF) if (tmr->self_ref == LUA_NOREF)
tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
//we return false if the timer is not idle and is not to be restarted //we return false if the timer is not idle and is not to be restarted
int idle = tmr->mode&TIMER_IDLE_FLAG; int idle = tmr->mode&TIMER_IDLE_FLAG;
if(!(idle || restart)){ if(!(idle || restart)){
lua_pushboolean(L, false); lua_pushboolean(L, false);
}else{ }else{
if (!idle) {os_timer_disarm(&tmr->os);} if (!idle) {os_timer_disarm(&tmr->os);}
tmr->mode &= ~TIMER_IDLE_FLAG; tmr->mode &= ~TIMER_IDLE_FLAG;
os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
lua_pushboolean(L, true); lua_pushboolean(L, true);
} }
return 1; return 1;
} }
// Lua: t:alarm( interval, repeat, function ) // Lua: t:alarm( interval, repeat, function )
static int tmr_alarm(lua_State* L){ static int tmr_alarm(lua_State* L){
tmr_register(L); tmr_register(L);
/* remove tmr.alarm's other then the 1st UD parameters from Lua stack. /* remove tmr.alarm's other then the 1st UD parameters from Lua stack.
tmr.start expects UD and optional restart parameter. */ tmr.start expects UD and optional restart parameter. */
lua_settop(L, 1); lua_settop(L, 1);
return tmr_start(L); return tmr_start(L);
} }
// Lua: t:stop() // Lua: t:stop()
static int tmr_stop(lua_State* L){ static int tmr_stop(lua_State* L){
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
int idle = tmr->mode == TIMER_MODE_OFF || (tmr->mode & TIMER_IDLE_FLAG); int idle = tmr->mode == TIMER_MODE_OFF || (tmr->mode & TIMER_IDLE_FLAG);
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
if(!idle) if(!idle)
os_timer_disarm(&tmr->os); os_timer_disarm(&tmr->os);
tmr->mode |= TIMER_IDLE_FLAG; tmr->mode |= TIMER_IDLE_FLAG;
lua_pushboolean(L, !idle); /* return false if the timer is idle (or not registered) */ lua_pushboolean(L, !idle); /* return false if the timer is idle (or not registered) */
return 1; return 1;
} }
#ifdef TIMER_SUSPEND_ENABLE #ifdef TIMER_SUSPEND_ENABLE
@ -179,174 +179,173 @@ static int tmr_stop(lua_State* L){
#define tmr_suspend_all tmr_suspend_removed #define tmr_suspend_all tmr_suspend_removed
#define tmr_resume_all tmr_suspend_removed #define tmr_resume_all tmr_suspend_removed
static int tmr_suspend_removed(lua_State* L){ static int tmr_suspend_removed(lua_State* L){
return luaL_error(L, TMR_SUSPEND_REMOVED_MSG); return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
} }
#endif #endif
// Lua: t:unregister() // Lua: t:unregister()
static int tmr_unregister(lua_State* L){ static int tmr_unregister(lua_State* L){
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref); luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref);
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
os_timer_disarm(&tmr->os); os_timer_disarm(&tmr->os);
tmr->mode = TIMER_MODE_OFF; tmr->mode = TIMER_MODE_OFF;
return 0; return 0;
} }
// Lua: t:interval( interval ) // Lua: t:interval( interval )
static int tmr_interval(lua_State* L){ static int tmr_interval(lua_State* L){
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
uint32_t interval = luaL_checkinteger(L, 2); uint32_t interval = luaL_checkinteger(L, 2);
luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR); luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
if(tmr->mode != TIMER_MODE_OFF){ if(tmr->mode != TIMER_MODE_OFF){
tmr->interval = interval; tmr->interval = interval;
if(!(tmr->mode&TIMER_IDLE_FLAG)){ if(!(tmr->mode&TIMER_IDLE_FLAG)){
os_timer_disarm(&tmr->os); os_timer_disarm(&tmr->os);
os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
} }
} }
return 0; return 0;
} }
// Lua: t:state() // Lua: t:state()
static int tmr_state(lua_State* L){ static int tmr_state(lua_State* L){
tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
if(tmr->mode == TIMER_MODE_OFF){ if(tmr->mode == TIMER_MODE_OFF){
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0); lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG)); lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG));
return 2; return 2;
} }
// Lua: tmr.wdclr() // Lua: tmr.wdclr()
static int tmr_wdclr( lua_State* L ){ static int tmr_wdclr( lua_State* L ){
system_soft_wdt_feed (); system_soft_wdt_feed ();
return 0; return 0;
} }
// The on ESP8266 system_rtc_clock_cali_proc() returns a fixed point value // The on ESP8266 system_rtc_clock_cali_proc() returns a fixed point value
// (12 bit fraction part), giving how many rtc clock ticks represent 1us. // (12 bit fraction part), giving how many rtc clock ticks represent 1us.
// The high 64 bits of the uint64_t multiplication are not needed) // The high 64 bits of the uint64_t multiplication are not needed)
static uint32_t rtc2usec(uint64_t rtc){ static uint32_t rtc2usec(uint64_t rtc){
return (rtc*rtc_time_cali)>>12; return (rtc*rtc_time_cali)>>12;
} }
// This returns the number of microseconds uptime. Note that it relies on // This returns the number of microseconds uptime. Note that it relies on
// the rtc clock, which is notoriously temperature dependent // the rtc clock, which is notoriously temperature dependent
inline static uint64_t rtc_timer_update(bool do_calibration){ inline static uint64_t rtc_timer_update(bool do_calibration){
if (do_calibration || rtc_time_cali==0) if (do_calibration || rtc_time_cali==0)
rtc_time_cali=system_rtc_clock_cali_proc(); rtc_time_cali=system_rtc_clock_cali_proc();
uint32_t current = system_get_rtc_time(); uint32_t current = system_get_rtc_time();
uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound
uint32_t us_since_last=rtc2usec(since_last); uint32_t us_since_last=rtc2usec(since_last);
uint64_t now=last_rtc_time_us+us_since_last; uint64_t now=last_rtc_time_us+us_since_last;
// Only update if at least 100ms has passed since we last updated. // Only update if at least 100ms has passed since we last updated.
// This prevents the rounding errors in rtc2usec from accumulating // This prevents the rounding errors in rtc2usec from accumulating
if (us_since_last>=100000){ if (us_since_last>=100000){
last_rtc_time=current; last_rtc_time=current;
last_rtc_time_us=now; last_rtc_time_us=now;
} }
return now; return now;
} }
void rtc_callback(void *arg){ void rtc_callback(void *arg){
rtc_timer_update(true); rtc_timer_update(true);
if(soft_watchdog > 0){ if(soft_watchdog >= 0){
soft_watchdog--; soft_watchdog--;
if(soft_watchdog == 0) if(soft_watchdog < 0)
system_restart(); system_restart();
} }
} }
// Lua: tmr.time() , return rtc time in second // Lua: tmr.time() , return rtc time in second
static int tmr_time( lua_State* L ){ static int tmr_time( lua_State* L ){
uint64_t us=rtc_timer_update(false); uint64_t us=rtc_timer_update(false);
lua_pushinteger(L, us/1000000); lua_pushinteger(L, us/1000000);
return 1; return 1;
} }
// Lua: tmr.softwd( value ) // Lua: tmr.softwd( value )
static int tmr_softwd( lua_State* L ){ static int tmr_softwd( lua_State* L ){
int t = luaL_checkinteger(L, 1); soft_watchdog = luaL_checkinteger(L, 1);
luaL_argcheck(L, t>0 , 2, "invalid time"); // NO check is required as negative Values mean that the timer is disabled.
soft_watchdog = t; return 0;
return 0;
} }
// Lua: tmr.create() // Lua: tmr.create()
static int tmr_create( lua_State *L ) { static int tmr_create( lua_State *L ) {
tmr_t *ud = (tmr_t *)lua_newuserdata(L, sizeof(*ud)); tmr_t *ud = (tmr_t *)lua_newuserdata(L, sizeof(*ud));
luaL_getmetatable(L, "tmr.timer"); luaL_getmetatable(L, "tmr.timer");
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
*ud = (tmr_t) {{0}, LUA_NOREF, LUA_NOREF, 0, TIMER_MODE_OFF}; *ud = (tmr_t) {{0}, LUA_NOREF, LUA_NOREF, 0, TIMER_MODE_OFF};
return 1; return 1;
} }
// Module function map // Module function map
LROT_BEGIN(tmr_dyn, NULL, LROT_MASK_GC_INDEX) LROT_BEGIN(tmr_dyn, NULL, LROT_MASK_GC_INDEX)
LROT_FUNCENTRY( __gc, tmr_unregister ) LROT_FUNCENTRY( __gc, tmr_unregister )
LROT_TABENTRY( __index, tmr_dyn ) LROT_TABENTRY( __index, tmr_dyn )
LROT_FUNCENTRY( register, tmr_register ) LROT_FUNCENTRY( register, tmr_register )
LROT_FUNCENTRY( alarm, tmr_alarm ) LROT_FUNCENTRY( alarm, tmr_alarm )
LROT_FUNCENTRY( start, tmr_start ) LROT_FUNCENTRY( start, tmr_start )
LROT_FUNCENTRY( stop, tmr_stop ) LROT_FUNCENTRY( stop, tmr_stop )
LROT_FUNCENTRY( unregister, tmr_unregister ) LROT_FUNCENTRY( unregister, tmr_unregister )
LROT_FUNCENTRY( state, tmr_state ) LROT_FUNCENTRY( state, tmr_state )
LROT_FUNCENTRY( interval, tmr_interval ) LROT_FUNCENTRY( interval, tmr_interval )
#ifdef TIMER_SUSPEND_ENABLE #ifdef TIMER_SUSPEND_ENABLE
LROT_FUNCENTRY( suspend, tmr_suspend ) LROT_FUNCENTRY( suspend, tmr_suspend )
LROT_FUNCENTRY( resume, tmr_resume ) LROT_FUNCENTRY( resume, tmr_resume )
#endif #endif
LROT_END(tmr_dyn, NULL, LROT_MASK_GC_INDEX) LROT_END(tmr_dyn, NULL, LROT_MASK_GC_INDEX)
LROT_BEGIN(tmr, NULL, 0) LROT_BEGIN(tmr, NULL, 0)
LROT_FUNCENTRY( delay, tmr_delay ) LROT_FUNCENTRY( delay, tmr_delay )
LROT_FUNCENTRY( now, tmr_now ) LROT_FUNCENTRY( now, tmr_now )
LROT_FUNCENTRY( wdclr, tmr_wdclr ) LROT_FUNCENTRY( wdclr, tmr_wdclr )
LROT_FUNCENTRY( softwd, tmr_softwd ) LROT_FUNCENTRY( softwd, tmr_softwd )
LROT_FUNCENTRY( time, tmr_time ) LROT_FUNCENTRY( time, tmr_time )
LROT_FUNCENTRY( ccount, tmr_ccount ) LROT_FUNCENTRY( ccount, tmr_ccount )
#ifdef TIMER_SUSPEND_ENABLE #ifdef TIMER_SUSPEND_ENABLE
LROT_FUNCENTRY( suspend_all, tmr_suspend_all ) LROT_FUNCENTRY( suspend_all, tmr_suspend_all )
LROT_FUNCENTRY( resume_all, tmr_resume_all ) LROT_FUNCENTRY( resume_all, tmr_resume_all )
#endif #endif
LROT_FUNCENTRY( create, tmr_create ) LROT_FUNCENTRY( create, tmr_create )
LROT_NUMENTRY( ALARM_SINGLE, TIMER_MODE_SINGLE ) LROT_NUMENTRY( ALARM_SINGLE, TIMER_MODE_SINGLE )
LROT_NUMENTRY( ALARM_SEMI, TIMER_MODE_SEMI ) LROT_NUMENTRY( ALARM_SEMI, TIMER_MODE_SEMI )
LROT_NUMENTRY( ALARM_AUTO, TIMER_MODE_AUTO ) LROT_NUMENTRY( ALARM_AUTO, TIMER_MODE_AUTO )
LROT_END(tmr, NULL, 0) LROT_END(tmr, NULL, 0)
#include "pm/swtimer.h" #include "pm/swtimer.h"
int luaopen_tmr( lua_State *L ){ int luaopen_tmr( lua_State *L ){
luaL_rometatable(L, "tmr.timer", LROT_TABLEREF(tmr_dyn)); luaL_rometatable(L, "tmr.timer", LROT_TABLEREF(tmr_dyn));
last_rtc_time=system_get_rtc_time(); // Right now is time 0 last_rtc_time=system_get_rtc_time(); // Right now is time 0
last_rtc_time_us=0; last_rtc_time_us=0;
os_timer_disarm(&rtc_timer); os_timer_disarm(&rtc_timer);
os_timer_setfn(&rtc_timer, rtc_callback, NULL); os_timer_setfn(&rtc_timer, rtc_callback, NULL);
os_timer_arm(&rtc_timer, 1000, 1); os_timer_arm(&rtc_timer, 1000, 1);
// The function rtc_callback calls the a function that calibrates the SoftRTC // 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 // for drift in the esp8266's clock. My guess: after the duration of light_sleep
// there is bound to be some drift in the clock, so a calibration is due. // there is bound to be some drift in the clock, so a calibration is due.
SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME); SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME);
// The function alarm_timer_common handles timers created by the developer via // The function alarm_timer_common handles timers created by the developer via
// tmr.create(). No reason not to resume the timers, so resume em'. // tmr.create(). No reason not to resume the timers, so resume em'.
SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME); SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME);
return 0; return 0;
} }
NODEMCU_MODULE(TMR, "tmr", tmr, luaopen_tmr); NODEMCU_MODULE(TMR, "tmr", tmr, luaopen_tmr);

View File

@ -89,3 +89,10 @@ N.testco('AUTO alarm coroutine', function(getCB, waitCB)
ok(true, "coroutine end") ok(true, "coroutine end")
end) end)
N.test('softwd set positive and negative values', function()
tmr.softwd(22)
tmr.softwd(0)
tmr.softwd(-1) -- disable it again
tmr.softwd(-22) -- disable it again
end)