Expunge integer timers (#2603)

This commit is contained in:
Nathaniel Wesley Filardo 2019-01-22 21:59:41 +00:00 committed by Marcel Stör
parent 6f3f1126d6
commit 0e89fb24ba
2 changed files with 210 additions and 248 deletions

View File

@ -16,7 +16,7 @@ tmr.delay() -- not changed
tmr.alarm() -- not changed tmr.alarm() -- not changed
tmr.stop() -- changed, see below. use tmr.unregister for old functionality tmr.stop() -- changed, see below. use tmr.unregister for old functionality
tmr.register(id, interval, mode, function) tmr.register(ref, interval, mode, function)
bind function with timer and set the interval in ms bind function with timer and set the interval in ms
the mode can be: the mode can be:
tmr.ALARM_SINGLE for a single run alarm tmr.ALARM_SINGLE for a single run alarm
@ -24,20 +24,20 @@ tmr.register(id, interval, mode, function)
tmr.ALARM_AUTO for a repating alarm tmr.ALARM_AUTO for a repating alarm
tmr.register does NOT start the timer tmr.register does NOT start the timer
tmr.alarm is a tmr.register & tmr.start macro tmr.alarm is a tmr.register & tmr.start macro
tmr.unregister(id) tmr.unregister(ref)
stop alarm, unbind function and clean up memory stop alarm, unbind function and clean up memory
not needed for ALARM_SINGLE, as it unregisters itself not needed for ALARM_SINGLE, as it unregisters itself
tmr.start(id) tmr.start(ref)
ret: bool ret: bool
start a alarm, returns true on success start a alarm, returns true on success
tmr.stop(id) tmr.stop(ref)
ret: bool ret: bool
stops a alarm, returns true on success stops a alarm, returns true on success
this call dose not free any memory, to do so use tmr.unregister this call dose not free any memory, to do so use tmr.unregister
stopped alarms can be started with start stopped alarms can be started with start
tmr.interval(id, interval) tmr.interval(ref, interval)
set alarm interval, running alarm will be restarted set alarm interval, running alarm will be restarted
tmr.state(id) tmr.state(ref)
ret: (bool, int) or nil ret: (bool, int) or nil
returns alarm status (true=started/false=stopped) and mode returns alarm status (true=started/false=stopped) and mode
nil if timer is unregistered nil if timer is unregistered
@ -73,7 +73,8 @@ 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, self_ref; sint32_t lua_ref; /* Reference to the callback function */
sint32_t self_ref; /* Reference to this structure as userdata */
uint32_t interval; uint32_t interval;
uint8_t mode; uint8_t mode;
}timer_struct_t; }timer_struct_t;
@ -93,7 +94,6 @@ static uint32_t last_rtc_time=0;
static uint64_t last_rtc_time_us=0; static uint64_t last_rtc_time_us=0;
static sint32_t soft_watchdog = -1; static sint32_t soft_watchdog = -1;
static timer_struct_t alarm_timers[NUM_TMR];
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){
@ -102,12 +102,7 @@ static void alarm_timer_common(void* arg){
if(tmr->lua_ref == LUA_NOREF) if(tmr->lua_ref == LUA_NOREF)
return; return;
lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref);
if (tmr->self_ref == LUA_REFNIL) {
uint32_t id = tmr - alarm_timers;
lua_pushinteger(L, id);
} else {
lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
}
//if the timer was set to single run we clean up after it //if the timer was set to single run we clean up after it
if(tmr->mode == TIMER_MODE_SINGLE){ if(tmr->mode == TIMER_MODE_SINGLE){
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref); luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
@ -148,19 +143,13 @@ static int tmr_now(lua_State* L){
} }
static timer_t tmr_get( lua_State *L, int stack ) { static timer_t tmr_get( lua_State *L, int stack ) {
// Deprecated: static 0-6 timers control by index. timer_t t = (timer_t)luaL_checkudata(L, stack, "tmr.timer");
luaL_argcheck(L, (lua_isuserdata(L, stack) || lua_isnumber(L, stack)), 1, "timer object or numerical ID expected"); if (t == NULL)
if (lua_isuserdata(L, stack)) { return (timer_t)luaL_error(L, "timer object expected");
return (timer_t)luaL_checkudata(L, stack, "tmr.timer"); return t;
} else {
uint32_t id = luaL_checkinteger(L, 1);
luaL_argcheck(L, platform_tmr_exists(id), 1, "invalid timer index");
return &alarm_timers[id];
}
return 0;
} }
// Lua: tmr.register( id / ref, interval, mode, function ) // Lua: tmr.register( ref, interval, mode, function )
static int tmr_register(lua_State* L){ static int tmr_register(lua_State* L){
timer_t tmr = tmr_get(L, 1); timer_t tmr = tmr_get(L, 1);
@ -403,19 +392,10 @@ static const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) }, { LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
{ LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) }, { LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) },
{ LSTRKEY( "time" ), LFUNCVAL( tmr_time ) }, { LSTRKEY( "time" ), LFUNCVAL( tmr_time ) },
{ LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
{ LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
#ifdef TIMER_SUSPEND_ENABLE #ifdef TIMER_SUSPEND_ENABLE
{ LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
{ LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) }, { LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) },
{ LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
{ LSTRKEY( "resume_all" ), LFUNCVAL( tmr_resume_all ) }, { LSTRKEY( "resume_all" ), LFUNCVAL( tmr_resume_all ) },
#endif #endif
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) },
{ LSTRKEY( "create" ), LFUNCVAL( tmr_create ) }, { LSTRKEY( "create" ), LFUNCVAL( tmr_create ) },
{ LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) }, { LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) }, { LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
@ -425,16 +405,8 @@ static const LUA_REG_TYPE tmr_map[] = {
#include "pm/swtimer.h" #include "pm/swtimer.h"
int luaopen_tmr( lua_State *L ){ int luaopen_tmr( lua_State *L ){
int i;
luaL_rometatable(L, "tmr.timer", (void *)tmr_dyn_map); luaL_rometatable(L, "tmr.timer", (void *)tmr_dyn_map);
for(i=0; i<NUM_TMR; i++){
alarm_timers[i].lua_ref = LUA_NOREF;
alarm_timers[i].self_ref = LUA_REFNIL;
alarm_timers[i].mode = TIMER_MODE_OFF;
os_timer_disarm(&alarm_timers[i].os);
}
last_rtc_time=system_get_rtc_time(); // Right now is time 0 last_rtc_time=system_get_rtc_time(); // Right now is time 0
last_rtc_time_us=0; last_rtc_time_us=0;

View File

@ -9,63 +9,27 @@ It is aimed at setting up regularly occurring tasks, timing out operations, and
What the tmr module is *not* however, is a time keeping module. While most timeouts are expressed in milliseconds or even microseconds, the accuracy is limited and compounding errors would lead to rather inaccurate time keeping. Consider using the [rtctime](rtctime.md) module for "wall clock" time. What the tmr module is *not* however, is a time keeping module. While most timeouts are expressed in milliseconds or even microseconds, the accuracy is limited and compounding errors would lead to rather inaccurate time keeping. Consider using the [rtctime](rtctime.md) module for "wall clock" time.
NodeMCU provides 7 static timers, numbered 0-6, and dynamic timer creation function [`tmr.create()`](#tmrcreate).
!!! attention !!! attention
Static timers are deprecated and will be removed later. Use the OO API initiated with [`tmr.create()`](#tmrcreate). NodeMCU formerly provided 7 static timers, numbered 0-6, which could be
used instead of OO API timers initiated with [`tmr.create()`](#tmrcreate).
## tmr.alarm() After a long period of deprecation, these were removed in 2019 Q1.
This is a convenience function combining [`tmr.register()`](#tmrregister) and [`tmr.start()`](#tmrstart) into a single call.
To free up the resources with this timer when done using it, call [`tmr.unregister()`](#tmrunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Syntax
`tmr.alarm([id/ref], interval_ms, mode, func())`
#### Parameters
- `id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
- `interval_ms` timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`tmr.unregister()`](#tmrunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`tmr.start()`](#tmrstart) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
- `func(timer)` callback function which is invoked with the timer object as an argument
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end
```
#### See also
- [`tmr.create()`](#tmrcreate)
- [`tmr.register()`](#tmrregister)
- [`tmr.start()`](#tmrstart)
- [`tmr.unregister()`](#tmrunregister)
## tmr.create() ## tmr.create()
Creates a dynamic timer object. Creates a dynamic timer object; see below for its method table.
Dynamic timer can be used instead of numeric ID in control functions. Also can be controlled in object-oriented way. Dynamic timer can be used instead of numeric ID in control functions. Also can be controlled in object-oriented way.
Functions supported in timer object: Functions supported in timer object:
- [`t:alarm()`](#tmralarm) - [`t:alarm()`](#tobjalarm)
- [`t:interval()`](#tmrinterval) - [`t:interval()`](#tobjinterval)
- [`t:register()`](#tmrregister) - [`t:register()`](#tobjregister)
- [`t:start()`](#tmrstart) - [`t:start()`](#tobjstart)
- [`t:state()`](#tmrstate) - [`t:state()`](#tobjstate)
- [`t:stop()`](#tmrstop) - [`t:stop()`](#tobjstop)
- [`t:unregister()`](#tmrunregister) - [`t:unregister()`](#tobjunregister)
#### Parameters #### Parameters
none none
@ -76,14 +40,8 @@ none
#### Example #### Example
```lua ```lua
local mytimer = tmr.create() local mytimer = tmr.create()
-- oo calling
mytimer:register(5000, tmr.ALARM_SINGLE, function (t) print("expired"); t:unregister() end) mytimer:register(5000, tmr.ALARM_SINGLE, function (t) print("expired"); t:unregister() end)
mytimer:start() mytimer:start()
-- with self parameter
tmr.register(mytimer, 5000, tmr.ALARM_SINGLE, function (t) print("expired"); tmr.unregister(t) end)
tmr.start(mytimer)
``` ```
## tmr.delay() ## tmr.delay()
@ -108,28 +66,6 @@ Also note that the actual amount of time delayed for may be noticeably greater,
tmr.delay(100) tmr.delay(100)
``` ```
## tmr.interval()
Changes a registered timer's expiry interval.
#### Syntax
`tmr.interval([id/ref], interval_ms)`
#### Parameters
- `id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
- `interval_ms` new timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
#### Returns
`nil`
#### Example
```lua
mytimer = tmr.create()
mytimer:register(10000, tmr.ALARM_AUTO, function() print("hey there") end)
mytimer:interval(3000) -- actually, 3 seconds is better!
mytimer:start()
```
## tmr.now() ## tmr.now()
Returns the system counter, which counts in microseconds. Limited to 31 bits, after that it wraps around back to zero. That is essential if you use this function to [debounce or throttle GPIO input](https://github.com/hackhitchin/esp8266-co-uk/issues/2). Returns the system counter, which counts in microseconds. Limited to 31 bits, after that it wraps around back to zero. That is essential if you use this function to [debounce or throttle GPIO input](https://github.com/hackhitchin/esp8266-co-uk/issues/2).
@ -149,39 +85,6 @@ print(tmr.now())
print(tmr.now()) print(tmr.now())
``` ```
## tmr.register()
Configures a timer and registers the callback function to call on expiry.
To free up the resources with this timer when done using it, call [`tmr.unregister()`](#tmrunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Syntax
`tmr.register([id/ref], interval_ms, mode, func())`
#### Parameters
- `id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
- `interval_ms` timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`tmr.unregister()`](#tmrunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`tmr.start()`](#tmrunregister) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
- `func(timer)` callback function which is invoked with the timer object as an argument
Note that registering does *not* start the alarm.
#### Returns
`nil`
#### Example
```lua
mytimer = tmr.create()
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
mytimer:start()
```
#### See also
- [`tmr.create()`](#tmrcreate)
- [`tmr.alarm()`](#tmralarm)
## tmr.softwd() ## tmr.softwd()
Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted. Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted.
@ -207,78 +110,6 @@ tmr.softwd(5)
complex_stuff_which_might_never_call_the_callback(on_success_callback) complex_stuff_which_might_never_call_the_callback(on_success_callback)
``` ```
## tmr.start()
Starts or restarts a previously configured timer.
#### Syntax
`tmr.start([id/ref])`
#### Parameters
`id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
mytimer = tmr.create()
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
if not mytimer:start() then print("uh oh") end
```
#### See also
- [`tmr.create()`](#tmrcreate)
- [`tmr.register()`](#tmrregister)
- [`tmr.stop()`](#tmrstop)
- [`tmr.unregister()`](#tmrunregister)
## tmr.state()
Checks the state of a timer.
#### Syntax
`tmr.state([id/ref])`
#### Parameters
`id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
#### Returns
(bool, int) or `nil`
If the specified timer is registered, returns whether it is currently started and its mode. If the timer is not registered, `nil` is returned.
#### Example
```lua
mytimer = tmr.create()
print(mytimer:state()) -- nil
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
running, mode = mytimer:state()
print("running: " .. tostring(running) .. ", mode: " .. mode) -- running: false, mode: 0
```
## tmr.stop()
Stops a running timer, but does *not* unregister it. A stopped timer can be restarted with [`tmr.start()`](#tmrstart).
#### Syntax
`tmr.stop([id/ref])`
#### Parameters
`id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
#### Returns
`true` if the timer was stopped, `false` on error
#### Example
```lua
mytimer = tmr.create()
if not mytimer:stop() then print("timer not stopped, not registered?") end
```
#### See also
- [`tmr.register()`](#tmrregister)
- [`tmr.stop()`](#tmrstop)
- [`tmr.unregister()`](#tmrunregister)
## tmr.time() ## tmr.time()
Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero. Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero.
@ -297,28 +128,6 @@ the system uptime, in seconds, possibly wrapped around
print("Uptime (probably):", tmr.time()) print("Uptime (probably):", tmr.time())
``` ```
## tmr.unregister()
Stops the timer (if running) and unregisters the associated callback.
This isn't necessary for one-shot timers (`tmr.ALARM_SINGLE`), as those automatically unregister themselves when fired.
#### Syntax
`tmr.unregister([id/ref])`
#### Parameters
`id`/`ref` timer id (0-6) or object, obsolete for OO API (→ [`tmr.create()`](#tmrcreate))
#### Returns
`nil`
#### Example
```lua
tmr.unregister(0)
```
#### See also
[`tmr.register()`](#tmrregister)
## tmr.wdclr() ## tmr.wdclr()
Feed the system watchdog. Feed the system watchdog.
@ -335,3 +144,184 @@ none
#### Returns #### Returns
`nil` `nil`
## Timer Object Methods
### tobj:alarm()
This is a convenience function combining [`tobj:register()`](#tobjregister) and [`tobj:start()`](#tobjstart) into a single call.
To free up the resources with this timer when done using it, call [`tobj:unregister()`](#tobjunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Syntax
`tobj:alarm(interval_ms, mode, func())`
#### Parameters
- `interval_ms` timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`unregister()`](#tobjunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`start()`](#tobjstart) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
- `func(timer)` callback function which is invoked with the timer object as an argument
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end
```
#### See also
- [`tobj:create()`](#tobjcreate)
- [`tobj:register()`](#tobjregister)
- [`tobj:start()`](#tobjstart)
- [`tobj:unregister()`](#tobjunregister)
### tobj:interval()
Changes a registered timer's expiry interval.
#### Syntax
`tobj:interval(interval_ms)`
#### Parameters
- `interval_ms` new timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
#### Returns
`nil`
#### Example
```lua
mytimer = tmr.create()
mytimer:register(10000, tmr.ALARM_AUTO, function() print("hey there") end)
mytimer:interval(3000) -- actually, 3 seconds is better!
mytimer:start()
```
### tobj:register()
Configures a timer and registers the callback function to call on expiry.
To free up the resources with this timer when done using it, call [`tobj:unregister()`](#tobjunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Syntax
`tobj:register(interval_ms, mode, func())`
#### Parameters
- `interval_ms` timer interval in milliseconds. Maximum value is 6870947 (1:54:30.947).
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`tobj:unregister()`](#tobjunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`tobj:start()`](#tobjunregister) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
- `func(timer)` callback function which is invoked with the timer object as an argument
Note that registering does *not* start the alarm.
#### Returns
`nil`
#### Example
```lua
mytimer = tmr.create()
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
mytimer:start()
```
#### See also
- [`tobj:create()`](#tobjcreate)
- [`tobj:alarm()`](#tobjalarm)
### tobj:start()
Starts or restarts a previously configured timer.
#### Syntax
`tobj:start()`
#### Parameters
None
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
mytimer = tmr.create()
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
if not mytimer:start() then print("uh oh") end
```
#### See also
- [`tobj:create()`](#tobjcreate)
- [`tobj:register()`](#tobjregister)
- [`tobj:stop()`](#tobjstop)
- [`tobj:unregister()`](#tobjunregister)
### tobj:state()
Checks the state of a timer.
#### Syntax
`tobj:state()`
#### Parameters
None
#### Returns
(bool, int) or `nil`
If the specified timer is registered, returns whether it is currently started and its mode. If the timer is not registered, `nil` is returned.
#### Example
```lua
mytimer = tmr.create()
print(mytimer:state()) -- nil
mytimer:register(5000, tmr.ALARM_SINGLE, function() print("hey there") end)
running, mode = mytimer:state()
print("running: " .. tostring(running) .. ", mode: " .. mode) -- running: false, mode: 0
```
### tobj:stop()
Stops a running timer, but does *not* unregister it. A stopped timer can be restarted with [`tobj:start()`](#tobjstart).
#### Syntax
`tobj:stop()`
#### Parameters
None
#### Returns
`true` if the timer was stopped, `false` on error
#### Example
```lua
mytimer = tmr.create()
if not mytimer:stop() then print("timer not stopped, not registered?") end
```
#### See also
- [`tobj:register()`](#tobjregister)
- [`tobj:stop()`](#tobjstop)
- [`tobj:unregister()`](#tobjunregister)
### tobj:unregister()
Stops the timer (if running) and unregisters the associated callback.
This isn't necessary for one-shot timers (`tmr.ALARM_SINGLE`), as those automatically unregister themselves when fired.
#### Syntax
`tobj:unregister()`
#### Parameters
None
#### Returns
`nil`
#### See also
[`tobj:register()`](#tobjregister)