Commit c1d2eb41 authored by Luna's avatar Luna
Browse files

rewrote the timer module from scratch

parent b4f0c2d1
// Module for interfacing with timer /*guys, srsly, turn on warnings in the makefile*/
#if defined(__GNUC__)
#pragma GCC diagnostic warning "-Wall"
#pragma GCC diagnostic warning "-Wextra"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
/*-------------------------------------
NEW TIMER API
---------------------------------------
tmr.wdclr() -- not changed
tmr.now() -- not changed
tmr.time() -- not changed
tmr.delay() -- not changed
tmr.alarm() -- not changed
tmr.stop() -- changed, see below. use tmr.unregister for old functionality
tmr.register(id, interval, mode, function)
bind function with timer and set the intercal in ms
the mode can be:
tmr.ALARM_SINGLE for a single run alarm
tmr.ALARM_SEMI for a multiple single run alarm
tmr.ALARM_AUTO for a repating alarm
tmr.register does NOT start the timer
tmr.alarm is a tmr.register & tmr.start macro
tmr.unregister(id)
stop alarm, unbind function and cleans up memory
not needed for ALARM_SINGLE, as it unregisters itself
tmr.start(id)
ret: bool
start a alarm, returns true on success
tmr.stop(id)
ret: bool
stops a alarm, returns true on success
this call dose not free any memory, to do so use tmr.unregister
stopped alarms can be started with start
tmr.state(id)
ret: (bool, int) or nil
returns alarm status (true=started/false=stopped) and mode
nil if timer is unregistered
*/
#define MIN_OPT_LEVEL 2
//#include "lua.h"
#include "lualib.h" #include "lualib.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "platform.h" #include "platform.h"
#include "auxmods.h" #include "auxmods.h"
#include "lrotable.h" #include "lrotable.h"
#include "lrodefs.h"
#include "c_types.h" #include "c_types.h"
static os_timer_t alarm_timer[NUM_TMR]; #define TIMER_MODE_OFF 3
static int alarm_timer_cb_ref[NUM_TMR] = {LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF}; #define TIMER_MODE_SINGLE 0
static bool alarm_timer_repeat[NUM_TMR]= {0,0,0,0,0,0,0}; #define TIMER_MODE_SEMI 2
#define TIMER_MODE_AUTO 1
void alarm_timer_common(lua_State* L, unsigned id){ #define TIMER_IDLE_FLAG (1<<7)
if(alarm_timer_cb_ref[id] == LUA_NOREF)
return; //well, the following are my assumptions
lua_rawgeti(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); //why, oh why is there no good documentation
if(alarm_timer_repeat[id]==0) //chinese companyes should learn from Atmel
{ extern void ets_timer_arm_new(os_timer_t* t, uint32_t milliseconds, uint32_t repeat_flag, uint32_t isMstimer);
if(alarm_timer_cb_ref[id] != LUA_NOREF) extern void ets_timer_disarm(os_timer_t* t);
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); extern void ets_timer_setfn(os_timer_t* t, os_timer_func_t *f, void *arg);
extern void ets_delay_us(uint32_t us);
} extern uint32_t system_get_time();
lua_call(L, 0, 0); extern uint32_t platform_tmr_exists(uint32_t t);
} extern uint32_t system_rtc_clock_cali_proc();
extern uint32_t system_get_rtc_time();
void alarm_timer_cb0(void *arg){ extern void system_restart();
if( !arg )
return; //in fact lua_State is constant, it's pointless to pass it around
alarm_timer_common((lua_State*)arg, 0); //but hey, whatever, I'll just pass it, still we waste 28B here
} typedef struct{
os_timer_t os;
void alarm_timer_cb1(void *arg){ lua_State* L;
if( !arg ) sint32_t lua_ref;
return; uint32_t interval;
alarm_timer_common((lua_State*)arg, 1); uint8_t mode;
} }timer_struct_t;
typedef timer_struct_t* timer_t;
void alarm_timer_cb2(void *arg){
if( !arg ) //everybody just love unions! riiiiight?
return; static union {
alarm_timer_common((lua_State*)arg, 2); uint64_t block;
} uint32_t part[2];
} rtc_time;
void alarm_timer_cb3(void *arg){ static sint32_t soft_watchdog = -1;
if( !arg ) static timer_struct_t alarm_timers[NUM_TMR];
return; static os_timer_t rtc_timer;
alarm_timer_common((lua_State*)arg, 3);
} static void alarm_timer_common(void* arg){
timer_t tmr = &alarm_timers[(uint32_t)arg];
void alarm_timer_cb4(void *arg){ if(tmr->lua_ref == LUA_NOREF || tmr->L == NULL)
if( !arg ) return;
return; lua_rawgeti(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
alarm_timer_common((lua_State*)arg, 4); //if the timer was set to single run we clean up after it
} if(tmr->mode == TIMER_MODE_SINGLE){
luaL_unref(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
void alarm_timer_cb5(void *arg){ tmr->lua_ref = LUA_NOREF;
if( !arg ) tmr->mode = TIMER_MODE_OFF;
return; }else if(tmr->mode == TIMER_MODE_SEMI){
alarm_timer_common((lua_State*)arg, 5); tmr->mode |= TIMER_IDLE_FLAG;
} }
lua_call(tmr->L, 0, 0);
void alarm_timer_cb6(void *arg){ }
if( !arg )
return; // Lua: tmr.delay( us )
alarm_timer_common((lua_State*)arg, 6); static int tmr_delay( lua_State* L ){
} sint32_t us = luaL_checkinteger(L, 1);
if(us <= 0)
typedef void (*alarm_timer_callback)(void *arg); return luaL_error(L, "wrong arg range");
static alarm_timer_callback alarm_timer_cb[NUM_TMR] = {alarm_timer_cb0,alarm_timer_cb1,alarm_timer_cb2,alarm_timer_cb3,alarm_timer_cb4,alarm_timer_cb5,alarm_timer_cb6}; while(us >= 1000000){
us -= 1000000;
// Lua: delay( us ) os_delay_us(1000000);
static int tmr_delay( lua_State* L ) WRITE_PERI_REG(0x60000914, 0x73);
{ }
s32 us; if(us>0){
us = luaL_checkinteger( L, 1 ); os_delay_us(us);
if ( us <= 0 ) WRITE_PERI_REG(0x60000914, 0x73);
return luaL_error( L, "wrong arg range" ); }
if(us<1000000) return 0;
{ }
os_delay_us( us );
WRITE_PERI_REG(0x60000914, 0x73); // Lua: tmr.now() , return system timer in us
return 0; static int tmr_now(lua_State* L){
} uint32_t now = 0x7FFFFFFF & system_get_time();
unsigned sec = (unsigned)us / 1000000; lua_pushinteger(L, now);
unsigned remain = (unsigned)us % 1000000; return 1;
int i = 0; }
for(i=0;i<sec;i++){
os_delay_us( 1000000 ); // Lua: tmr.register( id, interval, mode, function )
WRITE_PERI_REG(0x60000914, 0x73); static int tmr_register(lua_State* L){
} uint32_t id = luaL_checkinteger(L, 1);
if(remain>0) MOD_CHECK_ID(tmr, id);
os_delay_us( remain ); sint32_t interval = luaL_checkinteger(L, 2);
return 0; uint8_t mode = luaL_checkinteger(L, 3);
} //validate arguments
uint8_t args_valid = interval <= 0
// Lua: now() , return system timer in us || (mode != TIMER_MODE_SINGLE && mode != TIMER_MODE_SEMI && mode != TIMER_MODE_AUTO)
static int tmr_now( lua_State* L ) || (lua_type(L, 4) != LUA_TFUNCTION && lua_type(L, 4) != LUA_TLIGHTFUNCTION);
{ if(args_valid)
unsigned now = 0x7FFFFFFF & system_get_time(); return luaL_error(L, "wrong arg range");
lua_pushinteger( L, now ); //get the lua function reference
return 1; lua_pushvalue(L, 4);
} sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
timer_t tmr = &alarm_timers[id];
// Lua: alarm( id, interval, repeat, function ) if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
static int tmr_alarm( lua_State* L ) ets_timer_disarm(&tmr->os);
{ //there was a bug in this part, the second part of the following condition was missing
s32 interval; if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
unsigned repeat = 0; luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
int stack = 1; tmr->lua_ref = ref;
tmr->mode = mode|TIMER_IDLE_FLAG;
unsigned id = luaL_checkinteger( L, stack ); tmr->interval = interval;
stack++; tmr->L = L;
MOD_CHECK_ID( tmr, id ); ets_timer_setfn(&tmr->os, alarm_timer_common, (void*)id);
return 0;
interval = luaL_checkinteger( L, stack ); }
stack++;
if ( interval <= 0 ) // Lua: tmr.start( id )
return luaL_error( L, "wrong arg range" ); static int tmr_start(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
if ( lua_isnumber(L, stack) ){ MOD_CHECK_ID(tmr,id);
repeat = lua_tointeger(L, stack); timer_t tmr = &alarm_timers[id];
stack++; //we return false if the timer is not idle
if ( repeat != 1 && repeat != 0 ) if(!(tmr->mode&TIMER_IDLE_FLAG)){
return luaL_error( L, "wrong arg type" ); lua_pushboolean(L, 0);
alarm_timer_repeat[id]=repeat; }else{
} tmr->mode &= ~TIMER_IDLE_FLAG;
ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
// luaL_checkanyfunction(L, stack); lua_pushboolean(L, 1);
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ }
lua_pushvalue(L, stack); // copy argument (func) to the top of stack return 1;
if(alarm_timer_cb_ref[id] != LUA_NOREF) }
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
alarm_timer_cb_ref[id] = luaL_ref(L, LUA_REGISTRYINDEX); // Lua: tmr.alarm( id, interval, repeat, function )
} static int tmr_alarm(lua_State* L){
tmr_register(L);
os_timer_disarm(&(alarm_timer[id])); return tmr_start(L);
os_timer_setfn(&(alarm_timer[id]), (os_timer_func_t *)(alarm_timer_cb[id]), L); }
os_timer_arm(&(alarm_timer[id]), interval, repeat);
return 0; // Lua: tmr.stop( id )
} static int tmr_stop(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
// Lua: stop( id ) MOD_CHECK_ID(tmr,id);
static int tmr_stop( lua_State* L ) timer_t tmr = &alarm_timers[id];
{ //we return false if the timer is idle (of not registered)
unsigned id = luaL_checkinteger( L, 1 ); if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
MOD_CHECK_ID( tmr, id ); tmr->mode |= TIMER_IDLE_FLAG;
ets_timer_disarm(&tmr->os);
os_timer_disarm(&(alarm_timer[id])); lua_pushboolean(L, 1);
if(alarm_timer_cb_ref[id] != LUA_NOREF) }else{
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); lua_pushboolean(L, 0);
}
return 0; return 1;
} }
// Lua: tmr.unregister( id )
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];
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
ets_timer_disarm(&tmr->os);
if(tmr->lua_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
tmr->lua_ref = LUA_NOREF;
tmr->mode = TIMER_MODE_OFF;
return 0;
}
// Lua: tmr.state( id )
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];
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;
}
/*I left the led comments 'couse I don't know
why they are here*/
// extern void update_key_led(); // extern void update_key_led();
// Lua: wdclr() // Lua: tmr.wdclr()
static int tmr_wdclr( lua_State* L ) static int tmr_wdclr( lua_State* L ){
{ WRITE_PERI_REG(0x60000914, 0x73);
WRITE_PERI_REG(0x60000914, 0x73); // update_key_led();
// update_key_led(); return 0;
return 0; }
}
//system_rtc_clock_cali_proc() returns
static os_timer_t rtc_timer_updator; //a fixed point value (12 bit fraction part)
static uint32_t cur_count = 0; //it tells how many rtc clock ticks represent 1us.
static uint32_t rtc_10ms = 0; //the high 64 bits of the uint64_t multiplication
void rtc_timer_update_cb(void *arg){ //are unnedded (I did the math)
uint32_t t = (uint32_t)system_get_rtc_time(); static uint32_t rtc2sec(uint64_t rtc){
uint32_t delta = 0; uint64_t aku = system_rtc_clock_cali_proc();
if(t>=cur_count){ aku *= rtc;
delta = t-cur_count; return (aku>>12)/1000000;
}else{ }
delta = 0xFFFFFFF - cur_count + t + 1;
} //the following function workes, I just wrote it and didn't use it.
// uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count); /*static uint64_t sec2rtc(uint32_t sec){
// NODE_ERR("%x\n",t); uint64_t aku = (1<<20)/system_rtc_clock_cali_proc();
cur_count = t; aku *= sec;
uint32_t c = system_rtc_clock_cali_proc(); return (aku>>8)*1000000;
uint32_t itg = c >> 12; // ~=5 }*/
uint32_t dec = c & 0xFFF; // ~=2ff
rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000; inline static void rtc_timer_update(){
// TODO: store rtc_10ms to rtc memory. uint32_t current = system_get_rtc_time();
} if(rtc_time.part[0] > current) //overflow check
// Lua: time() , return rtc time in second rtc_time.part[1]++;
static int tmr_time( lua_State* L ) rtc_time.part[0] = current;
{ }
uint32_t local = rtc_10ms;
lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF ); void rtc_callback(void *arg){
return 1; rtc_timer_update();
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 ){
rtc_timer_update();
lua_pushinteger(L, rtc2sec(rtc_time.block));
return 1;
}
// Lua: tmr.softwd( value )
static int tmr_softwd( lua_State* L ){
soft_watchdog = luaL_checkinteger(L, 1);
return 0;
} }
// Module function map // Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE tmr_map[] =
{
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
{ LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
{ LSTRKEY( "time" ), LFUNCVAL( tmr_time ) },
#if LUA_OPTIMIZE_MEMORY > 0
const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
{ LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
{ LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) },
{ 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 ) },
{ LSTRKEY( "unregister" ), LFUNCVAL ( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL ( tmr_state ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
{ LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
#endif #endif
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
LUALIB_API int luaopen_tmr( lua_State *L ) LUALIB_API int luaopen_tmr( lua_State *L ){
{ int i;
int i = 0; for(i=0; i<NUM_TMR; i++){
for(i=0;i<NUM_TMR;i++){ alarm_timers[i].lua_ref = LUA_NOREF;
os_timer_disarm(&(alarm_timer[i])); alarm_timers[i].mode = TIMER_MODE_OFF;
os_timer_setfn(&(alarm_timer[i]), (os_timer_func_t *)(alarm_timer_cb[i]), L); ets_timer_disarm(&alarm_timers[i].os);
} }
rtc_time.block = 0;
os_timer_disarm(&rtc_timer_updator); ets_timer_disarm(&rtc_timer);
os_timer_setfn(&rtc_timer_updator, (os_timer_func_t *)(rtc_timer_update_cb), NULL); ets_timer_setfn(&rtc_timer, rtc_callback, NULL);
os_timer_arm(&rtc_timer_updator, 500, 1); ets_timer_arm_new(&rtc_timer, 1000, 1, 1);
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
return 0; return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0 #else
luaL_register( L, AUXLIB_TMR, tmr_map ); luaL_register( L, AUXLIB_TMR, tmr_map );
// Add constants lua_pushvalue( L, -1 );
lua_setmetatable( L, -2 );
return 1; MOD_REG_NUMBER( L, "ALARM_SINGLE", TIMER_MODE_SINGLE );
#endif // #if LUA_OPTIMIZE_MEMORY > 0 MOD_REG_NUMBER( L, "ALARM_SEMI", TIMER_MODE_SEMI );
MOD_REG_NUMBER( L, "ALARM_AUTO", TIMER_MODE_AUTO );
return 1;
#endif
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment