diff --git a/app/modules/tmr.c b/app/modules/tmr.c index b47af1c4..8e52708f 100644 --- a/app/modules/tmr.c +++ b/app/modules/tmr.c @@ -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); typedef struct{ - os_timer_t os; - sint32_t lua_ref; /* Reference to registered callback function */ - sint32_t self_ref; /* Reference to UD registered slot */ - uint32_t interval; - uint8_t mode; + os_timer_t os; + sint32_t lua_ref; /* Reference to registered callback function */ + sint32_t self_ref; /* Reference to UD registered slot */ + uint32_t interval; + uint8_t mode; } tmr_t; // 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 void alarm_timer_common(void* arg){ - tmr_t *tmr = (tmr_t *) arg; - if(tmr->lua_ref > 0) { - lua_State* L = lua_getstate(); - lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref); - lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref); - if (tmr->mode != TIMER_MODE_AUTO) { - if(tmr->mode == TIMER_MODE_SINGLE) { - luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref); - luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); - tmr->mode = TIMER_MODE_OFF; - } else if (tmr->mode == TIMER_MODE_SEMI) { - tmr->mode |= TIMER_IDLE_FLAG; - luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); - } - } - luaL_pcallx(L, 1, 0); - } + tmr_t *tmr = (tmr_t *) arg; + if(tmr->lua_ref > 0) { + lua_State* L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref); + if (tmr->mode != TIMER_MODE_AUTO) { + if(tmr->mode == TIMER_MODE_SINGLE) { + luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref); + luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); + tmr->mode = TIMER_MODE_OFF; + } else if (tmr->mode == TIMER_MODE_SEMI) { + tmr->mode |= TIMER_IDLE_FLAG; + luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); + } + } + luaL_pcallx(L, 1, 0); + } } // Lua: tmr.delay( us ) static int tmr_delay( lua_State* L ){ - sint32_t us = luaL_checkinteger(L, 1); - luaL_argcheck(L, us>0, 1, "wrong arg range"); - while(us > 0){ - os_delay_us(us >= 1000000 ? 1000000 : us); - system_soft_wdt_feed (); - us -= 1000000; - } - return 0; + sint32_t us = luaL_checkinteger(L, 1); + luaL_argcheck(L, us>0, 1, "wrong arg range"); + while(us > 0){ + os_delay_us(us >= 1000000 ? 1000000 : us); + system_soft_wdt_feed (); + us -= 1000000; + } + return 0; } // Lua: tmr.now() , return system timer in us static int tmr_now(lua_State* L){ - lua_pushinteger(L, (uint32_t) (0x7FFFFFFF & system_get_time())); - return 1; + lua_pushinteger(L, (uint32_t) (0x7FFFFFFF & system_get_time())); + return 1; } // Lua: tmr.ccount() , returns CCOUNT register static int tmr_ccount(lua_State* L){ - lua_pushinteger(L, CCOUNT_REG); - return 1; + lua_pushinteger(L, CCOUNT_REG); + return 1; } /* @@ -106,69 +106,69 @@ static int tmr_ccount(lua_State* L){ // Lua: t:register( interval, mode, function ) static int tmr_register(lua_State* L) { - tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); - uint32_t interval = luaL_checkinteger(L, 2); - uint8_t mode = luaL_checkinteger(L, 3); + tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); + uint32_t interval = luaL_checkinteger(L, 2); + uint8_t mode = luaL_checkinteger(L, 3); - 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, lua_isfunction(L, 4), 4, "Must be function"); + 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, lua_isfunction(L, 4), 4, "Must be function"); - //get the lua function reference - lua_pushvalue(L, 4); - if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) - os_timer_disarm(&tmr->os); - luaL_reref(L, LUA_REGISTRYINDEX, &tmr->lua_ref); - tmr->mode = mode|TIMER_IDLE_FLAG; - tmr->interval = interval; - os_timer_setfn(&tmr->os, alarm_timer_common, tmr); - return 0; + //get the lua function reference + lua_pushvalue(L, 4); + if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) + os_timer_disarm(&tmr->os); + luaL_reref(L, LUA_REGISTRYINDEX, &tmr->lua_ref); + tmr->mode = mode|TIMER_IDLE_FLAG; + tmr->interval = interval; + os_timer_setfn(&tmr->os, alarm_timer_common, tmr); + return 0; } // Lua: t:start( [restart] ) static int tmr_start(lua_State* L){ - tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); - lua_settop(L, 2); - luaL_argcheck(L, lua_isboolean(L, 2) || lua_isnil(L, 2), 2, "boolean expected"); - int restart = lua_toboolean(L, 2); + tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); + lua_settop(L, 2); + luaL_argcheck(L, lua_isboolean(L, 2) || lua_isnil(L, 2), 2, "boolean expected"); + int restart = lua_toboolean(L, 2); - lua_settop(L, 1); /* we need to have userdata on top of the stack */ - if (tmr->self_ref == LUA_NOREF) - tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_settop(L, 1); /* we need to have userdata on top of the stack */ + if (tmr->self_ref == LUA_NOREF) + tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); - //we return false if the timer is not idle and is not to be restarted - int idle = tmr->mode&TIMER_IDLE_FLAG; - if(!(idle || restart)){ - lua_pushboolean(L, false); - }else{ - if (!idle) {os_timer_disarm(&tmr->os);} - tmr->mode &= ~TIMER_IDLE_FLAG; - os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); - lua_pushboolean(L, true); - } - return 1; + //we return false if the timer is not idle and is not to be restarted + int idle = tmr->mode&TIMER_IDLE_FLAG; + if(!(idle || restart)){ + lua_pushboolean(L, false); + }else{ + if (!idle) {os_timer_disarm(&tmr->os);} + tmr->mode &= ~TIMER_IDLE_FLAG; + os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); + lua_pushboolean(L, true); + } + return 1; } // Lua: t:alarm( interval, repeat, function ) static int tmr_alarm(lua_State* L){ - tmr_register(L); - /* remove tmr.alarm's other then the 1st UD parameters from Lua stack. - tmr.start expects UD and optional restart parameter. */ - lua_settop(L, 1); - return tmr_start(L); + tmr_register(L); + /* remove tmr.alarm's other then the 1st UD parameters from Lua stack. + tmr.start expects UD and optional restart parameter. */ + lua_settop(L, 1); + return tmr_start(L); } // Lua: t:stop() static int tmr_stop(lua_State* L){ - tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); - int idle = tmr->mode == TIMER_MODE_OFF || (tmr->mode & TIMER_IDLE_FLAG); - luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); + tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); + int idle = tmr->mode == TIMER_MODE_OFF || (tmr->mode & TIMER_IDLE_FLAG); + luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref); - if(!idle) - os_timer_disarm(&tmr->os); - tmr->mode |= TIMER_IDLE_FLAG; - lua_pushboolean(L, !idle); /* return false if the timer is idle (or not registered) */ - return 1; + if(!idle) + os_timer_disarm(&tmr->os); + tmr->mode |= TIMER_IDLE_FLAG; + lua_pushboolean(L, !idle); /* return false if the timer is idle (or not registered) */ + return 1; } #ifdef TIMER_SUSPEND_ENABLE @@ -179,174 +179,173 @@ static int tmr_stop(lua_State* L){ #define tmr_suspend_all tmr_suspend_removed #define tmr_resume_all tmr_suspend_removed 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 // Lua: t:unregister() static int tmr_unregister(lua_State* L){ - 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->lua_ref); - if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) - os_timer_disarm(&tmr->os); - tmr->mode = TIMER_MODE_OFF; - return 0; + 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->lua_ref); + if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF) + os_timer_disarm(&tmr->os); + tmr->mode = TIMER_MODE_OFF; + return 0; } // Lua: t:interval( interval ) static int tmr_interval(lua_State* L){ - tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); - uint32_t interval = luaL_checkinteger(L, 2); - luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR); - if(tmr->mode != TIMER_MODE_OFF){ - tmr->interval = interval; - if(!(tmr->mode&TIMER_IDLE_FLAG)){ - os_timer_disarm(&tmr->os); - os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); - } - } - return 0; + tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); + uint32_t interval = luaL_checkinteger(L, 2); + luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR); + if(tmr->mode != TIMER_MODE_OFF){ + tmr->interval = interval; + if(!(tmr->mode&TIMER_IDLE_FLAG)){ + os_timer_disarm(&tmr->os); + os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO); + } + } + return 0; } // Lua: t:state() static int tmr_state(lua_State* L){ - tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); - if(tmr->mode == TIMER_MODE_OFF){ - lua_pushnil(L); - return 1; - } + tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer"); + if(tmr->mode == TIMER_MODE_OFF){ + lua_pushnil(L); + return 1; + } - lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0); - lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG)); - return 2; + lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0); + lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG)); + return 2; } // Lua: tmr.wdclr() static int tmr_wdclr( lua_State* L ){ - system_soft_wdt_feed (); - return 0; + system_soft_wdt_feed (); + return 0; } // 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. // The high 64 bits of the uint64_t multiplication are not needed) 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 // the rtc clock, which is notoriously temperature dependent inline static uint64_t rtc_timer_update(bool do_calibration){ - if (do_calibration || rtc_time_cali==0) - rtc_time_cali=system_rtc_clock_cali_proc(); + if (do_calibration || rtc_time_cali==0) + rtc_time_cali=system_rtc_clock_cali_proc(); - uint32_t current = system_get_rtc_time(); - uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound - uint32_t us_since_last=rtc2usec(since_last); - uint64_t now=last_rtc_time_us+us_since_last; + uint32_t current = system_get_rtc_time(); + uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound + uint32_t us_since_last=rtc2usec(since_last); + uint64_t now=last_rtc_time_us+us_since_last; - // Only update if at least 100ms has passed since we last updated. - // This prevents the rounding errors in rtc2usec from accumulating - if (us_since_last>=100000){ - last_rtc_time=current; - last_rtc_time_us=now; - } - return now; + // Only update if at least 100ms has passed since we last updated. + // This prevents the rounding errors in rtc2usec from accumulating + if (us_since_last>=100000){ + last_rtc_time=current; + last_rtc_time_us=now; + } + return now; } void rtc_callback(void *arg){ - rtc_timer_update(true); - if(soft_watchdog > 0){ - soft_watchdog--; - if(soft_watchdog == 0) - system_restart(); - } + rtc_timer_update(true); + if(soft_watchdog >= 0){ + soft_watchdog--; + if(soft_watchdog < 0) + system_restart(); + } } // Lua: tmr.time() , return rtc time in second static int tmr_time( lua_State* L ){ - uint64_t us=rtc_timer_update(false); - lua_pushinteger(L, us/1000000); - return 1; + uint64_t us=rtc_timer_update(false); + lua_pushinteger(L, us/1000000); + return 1; } // Lua: tmr.softwd( value ) static int tmr_softwd( lua_State* L ){ - int t = luaL_checkinteger(L, 1); - luaL_argcheck(L, t>0 , 2, "invalid time"); - soft_watchdog = t; - return 0; + soft_watchdog = luaL_checkinteger(L, 1); + // NO check is required as negative Values mean that the timer is disabled. + return 0; } // Lua: tmr.create() static int tmr_create( lua_State *L ) { - tmr_t *ud = (tmr_t *)lua_newuserdata(L, sizeof(*ud)); - luaL_getmetatable(L, "tmr.timer"); - lua_setmetatable(L, -2); - *ud = (tmr_t) {{0}, LUA_NOREF, LUA_NOREF, 0, TIMER_MODE_OFF}; - return 1; + tmr_t *ud = (tmr_t *)lua_newuserdata(L, sizeof(*ud)); + luaL_getmetatable(L, "tmr.timer"); + lua_setmetatable(L, -2); + *ud = (tmr_t) {{0}, LUA_NOREF, LUA_NOREF, 0, TIMER_MODE_OFF}; + return 1; } // Module function map LROT_BEGIN(tmr_dyn, NULL, LROT_MASK_GC_INDEX) - LROT_FUNCENTRY( __gc, tmr_unregister ) - LROT_TABENTRY( __index, tmr_dyn ) - LROT_FUNCENTRY( register, tmr_register ) - LROT_FUNCENTRY( alarm, tmr_alarm ) - LROT_FUNCENTRY( start, tmr_start ) - LROT_FUNCENTRY( stop, tmr_stop ) - LROT_FUNCENTRY( unregister, tmr_unregister ) - LROT_FUNCENTRY( state, tmr_state ) - LROT_FUNCENTRY( interval, tmr_interval ) + LROT_FUNCENTRY( __gc, tmr_unregister ) + LROT_TABENTRY( __index, tmr_dyn ) + LROT_FUNCENTRY( register, tmr_register ) + LROT_FUNCENTRY( alarm, tmr_alarm ) + LROT_FUNCENTRY( start, tmr_start ) + LROT_FUNCENTRY( stop, tmr_stop ) + LROT_FUNCENTRY( unregister, tmr_unregister ) + LROT_FUNCENTRY( state, tmr_state ) + LROT_FUNCENTRY( interval, tmr_interval ) #ifdef TIMER_SUSPEND_ENABLE - LROT_FUNCENTRY( suspend, tmr_suspend ) - LROT_FUNCENTRY( resume, tmr_resume ) + LROT_FUNCENTRY( suspend, tmr_suspend ) + LROT_FUNCENTRY( resume, tmr_resume ) #endif LROT_END(tmr_dyn, NULL, LROT_MASK_GC_INDEX) LROT_BEGIN(tmr, NULL, 0) - LROT_FUNCENTRY( delay, tmr_delay ) - LROT_FUNCENTRY( now, tmr_now ) - LROT_FUNCENTRY( wdclr, tmr_wdclr ) - LROT_FUNCENTRY( softwd, tmr_softwd ) - LROT_FUNCENTRY( time, tmr_time ) - LROT_FUNCENTRY( ccount, tmr_ccount ) + LROT_FUNCENTRY( delay, tmr_delay ) + LROT_FUNCENTRY( now, tmr_now ) + LROT_FUNCENTRY( wdclr, tmr_wdclr ) + LROT_FUNCENTRY( softwd, tmr_softwd ) + LROT_FUNCENTRY( time, tmr_time ) + LROT_FUNCENTRY( ccount, tmr_ccount ) #ifdef TIMER_SUSPEND_ENABLE - LROT_FUNCENTRY( suspend_all, tmr_suspend_all ) - LROT_FUNCENTRY( resume_all, tmr_resume_all ) + LROT_FUNCENTRY( suspend_all, tmr_suspend_all ) + LROT_FUNCENTRY( resume_all, tmr_resume_all ) #endif - LROT_FUNCENTRY( create, tmr_create ) - LROT_NUMENTRY( ALARM_SINGLE, TIMER_MODE_SINGLE ) - LROT_NUMENTRY( ALARM_SEMI, TIMER_MODE_SEMI ) - LROT_NUMENTRY( ALARM_AUTO, TIMER_MODE_AUTO ) + LROT_FUNCENTRY( create, tmr_create ) + LROT_NUMENTRY( ALARM_SINGLE, TIMER_MODE_SINGLE ) + LROT_NUMENTRY( ALARM_SEMI, TIMER_MODE_SEMI ) + LROT_NUMENTRY( ALARM_AUTO, TIMER_MODE_AUTO ) LROT_END(tmr, NULL, 0) #include "pm/swtimer.h" 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_us=0; + last_rtc_time=system_get_rtc_time(); // Right now is time 0 + last_rtc_time_us=0; - os_timer_disarm(&rtc_timer); - os_timer_setfn(&rtc_timer, rtc_callback, NULL); - os_timer_arm(&rtc_timer, 1000, 1); + os_timer_disarm(&rtc_timer); + os_timer_setfn(&rtc_timer, rtc_callback, NULL); + os_timer_arm(&rtc_timer, 1000, 1); - // 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 is bound to be some drift in the clock, so a calibration is due. - 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 is bound to be some drift in the clock, so a calibration is due. + SWTIMER_REG_CB(rtc_callback, 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'. - 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'. + SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME); - return 0; + return 0; } NODEMCU_MODULE(TMR, "tmr", tmr, luaopen_tmr); diff --git a/tests/NTest_tmr.lua b/tests/NTest_tmr.lua index 60ba795a..2b77ce70 100644 --- a/tests/NTest_tmr.lua +++ b/tests/NTest_tmr.lua @@ -89,3 +89,10 @@ N.testco('AUTO alarm coroutine', function(getCB, waitCB) ok(true, "coroutine 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) +