Skip to content

Commit

Permalink
Dynamic timers support
Browse files Browse the repository at this point in the history
  • Loading branch information
djphoenix committed Jul 28, 2016
1 parent f9875f6 commit c25b250
Showing 1 changed file with 104 additions and 30 deletions.
134 changes: 104 additions & 30 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,7 +95,7 @@ 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;
Expand All @@ -108,7 +108,13 @@ 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->self_ref == LUA_REFNIL) {
uint32_t id = tmr - alarm_timers;
lua_pushinteger(L, id);
} else {
lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
}
lua_call(L, 1, 0);
}

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

// Lua: tmr.register( id, interval, mode, function )
static int tmr_get( lua_State *L, int stack, timer_t *tmr ) {
if (lua_isuserdata(L, stack)) {
*tmr = (timer_t)luaL_checkudata(L, stack, "tmr.timer");
if (!*tmr) return luaL_error(L, "invalid userdata");
} else {
uint32_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr, id);
*tmr = &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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

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");
//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 +175,20 @@ 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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

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 +200,22 @@ 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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

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 +227,16 @@ 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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

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,11 +246,11 @@ 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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

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){
Expand All @@ -230,11 +263,11 @@ 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 = NULL; int res;
if ((res = tmr_get(L, 1, &tmr)) != 0) return res;

if(tmr->mode == TIMER_MODE_OFF){
lua_pushnil(L);
return 1;
Expand Down Expand Up @@ -307,8 +340,44 @@ 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;
}

// Lua: tmr.delete()
static int tmr_delete( lua_State *L ) {
timer_t ud = (timer_t)luaL_checkudata(L, 1, "tmr.timer");
if (!ud) return luaL_error(L, "wrong userdata");
ets_timer_disarm(&ud->os);
luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); ud->self_ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, ud->lua_ref); ud->lua_ref = LUA_NOREF;
return 0;
}

// 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_delete ) },
{ 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 @@ -322,6 +391,7 @@ static const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
{ 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 +400,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 Down

0 comments on commit c25b250

Please sign in to comment.