Skip to content

Commit

Permalink
Add support for dynamic timers, deprecating the static ones (#1424)
Browse files Browse the repository at this point in the history
  • Loading branch information
djphoenix authored and marcelstoer committed Aug 2, 2016
1 parent a499716 commit f1afe7b
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 50 deletions.
133 changes: 98 additions & 35 deletions app/modules/tmr.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static const char* MAX_TIMEOUT_ERR_STR = "Range: 1-"STRINGIFY(MAX_TIMEOUT_DEF);

typedef struct{
os_timer_t os;
sint32_t lua_ref;
sint32_t lua_ref, self_ref;
uint32_t interval;
uint8_t mode;
}timer_struct_t;
Expand All @@ -95,11 +95,17 @@ static timer_struct_t alarm_timers[NUM_TMR];
static os_timer_t rtc_timer;

static void alarm_timer_common(void* arg){
timer_t tmr = &alarm_timers[(uint32_t)arg];
timer_t tmr = (timer_t)arg;
lua_State* L = lua_getstate();
if(tmr->lua_ref == LUA_NOREF)
return;
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);
}
//if the timer was set to single run we clean up after it
if(tmr->mode == TIMER_MODE_SINGLE){
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
Expand All @@ -108,7 +114,11 @@ static void alarm_timer_common(void* arg){
}else if(tmr->mode == TIMER_MODE_SEMI){
tmr->mode |= TIMER_IDLE_FLAG;
}
lua_call(L, 0, 0);
if (tmr->mode != TIMER_MODE_AUTO && tmr->self_ref != LUA_REFNIL) {
luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
tmr->self_ref = LUA_NOREF;
}
lua_call(L, 1, 0);
}

// Lua: tmr.delay( us )
Expand All @@ -135,20 +145,32 @@ static int tmr_now(lua_State* L){
return 1;
}

// Lua: tmr.register( id, interval, mode, function )
static timer_t tmr_get( lua_State *L, int stack ) {
// Deprecated: static 0-6 timers control by index.
luaL_argcheck(L, (lua_isuserdata(L, stack) || lua_isnumber(L, stack)), 1, "timer object or numerical ID expected");
if (lua_isuserdata(L, stack)) {
return (timer_t)luaL_checkudata(L, stack, "tmr.timer");
} 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 )
static int tmr_register(lua_State* L){
uint32_t id = luaL_checkinteger(L, 1);
timer_t tmr = tmr_get(L, 1);

uint32_t interval = luaL_checkinteger(L, 2);
uint8_t mode = luaL_checkinteger(L, 3);
//Check if provided parameters are valid
MOD_CHECK_ID(tmr, id);

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_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION), 4, "Must be function");
luaL_argcheck(L, (mode == TIMER_MODE_SINGLE || mode == TIMER_MODE_SEMI || mode == TIMER_MODE_AUTO), 3, "Invalid mode");
luaL_argcheck(L, (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION), 4, "Must be function");
//get the lua function reference
lua_pushvalue(L, 4);
sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
timer_t tmr = &alarm_timers[id];
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
ets_timer_disarm(&tmr->os);
//there was a bug in this part, the second part of the following condition was missing
Expand All @@ -157,15 +179,19 @@ static int tmr_register(lua_State* L){
tmr->lua_ref = ref;
tmr->mode = mode|TIMER_IDLE_FLAG;
tmr->interval = interval;
ets_timer_setfn(&tmr->os, alarm_timer_common, (void*)id);
ets_timer_setfn(&tmr->os, alarm_timer_common, tmr);
return 0;
}

// Lua: tmr.start( id )
// Lua: tmr.start( id / ref )
static int tmr_start(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
timer_t tmr = tmr_get(L, 1);

if (tmr->self_ref == LUA_NOREF) {
lua_pushvalue(L, 1);
tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}

//we return false if the timer is not idle
if(!(tmr->mode&TIMER_IDLE_FLAG)){
lua_pushboolean(L, 0);
Expand All @@ -177,17 +203,21 @@ static int tmr_start(lua_State* L){
return 1;
}

// Lua: tmr.alarm( id, interval, repeat, function )
// Lua: tmr.alarm( id / ref, interval, repeat, function )
static int tmr_alarm(lua_State* L){
tmr_register(L);
return tmr_start(L);
}

// Lua: tmr.stop( id )
// Lua: tmr.stop( id / ref )
static int tmr_stop(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
timer_t tmr = tmr_get(L, 1);

if (tmr->self_ref != LUA_REFNIL) {
luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
tmr->self_ref = LUA_NOREF;
}

//we return false if the timer is idle (of not registered)
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
tmr->mode |= TIMER_IDLE_FLAG;
Expand All @@ -199,11 +229,15 @@ static int tmr_stop(lua_State* L){
return 1;
}

// Lua: tmr.unregister( id )
// Lua: tmr.unregister( id / ref )
static int tmr_unregister(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
timer_t tmr = tmr_get(L, 1);

if (tmr->self_ref != LUA_REFNIL) {
luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
tmr->self_ref = LUA_NOREF;
}

if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
ets_timer_disarm(&tmr->os);
if(tmr->lua_ref != LUA_NOREF)
Expand All @@ -213,13 +247,12 @@ static int tmr_unregister(lua_State* L){
return 0;
}

// Lua: tmr.interval( id, interval )
// Lua: tmr.interval( id / ref, interval )
static int tmr_interval(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
timer_t tmr = tmr_get(L, 1);

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){
tmr->interval = interval;
if(!(tmr->mode&TIMER_IDLE_FLAG)){
Expand All @@ -230,11 +263,10 @@ static int tmr_interval(lua_State* L){
return 0;
}

// Lua: tmr.state( id )
// Lua: tmr.state( id / ref )
static int tmr_state(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
timer_t tmr = tmr_get(L, 1);

if(tmr->mode == TIMER_MODE_OFF){
lua_pushnil(L);
return 1;
Expand Down Expand Up @@ -307,8 +339,34 @@ static int tmr_softwd( lua_State* L ){
return 0;
}

// Lua: tmr.create()
static int tmr_create( lua_State *L ) {
timer_t ud = (timer_t)lua_newuserdata(L, sizeof(timer_struct_t));
if (!ud) return luaL_error(L, "not enough memory");
luaL_getmetatable(L, "tmr.timer");
lua_setmetatable(L, -2);
ud->lua_ref = LUA_NOREF;
ud->self_ref = LUA_NOREF;
ud->mode = TIMER_MODE_OFF;
ets_timer_disarm(&ud->os);
return 1;
}

// Module function map

static const LUA_REG_TYPE tmr_dyn_map[] = {
{ LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
{ LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
{ LSTRKEY( "__gc" ), LFUNCVAL( tmr_unregister ) },
{ LSTRKEY( "__index" ), LROVAL( tmr_dyn_map ) },
{ LNILKEY, LNILVAL }
};

static const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
Expand All @@ -321,7 +379,8 @@ static const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
{ LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) },
{ LSTRKEY( "create" ), LFUNCVAL( tmr_create ) },
{ LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
{ LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
Expand All @@ -330,8 +389,12 @@ static const LUA_REG_TYPE tmr_map[] = {

int luaopen_tmr( lua_State *L ){
int i;

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;
ets_timer_disarm(&alarm_timers[i].os);
}
Expand All @@ -341,7 +404,7 @@ int luaopen_tmr( lua_State *L ){
ets_timer_disarm(&rtc_timer);
ets_timer_setfn(&rtc_timer, rtc_callback, NULL);
ets_timer_arm_new(&rtc_timer, 1000, 1, 1);
return 0;
return 0;
}

NODEMCU_MODULE(TMR, "tmr", tmr_map, luaopen_tmr);
Loading

0 comments on commit f1afe7b

Please sign in to comment.