diff --git a/app/modules/tmr.c b/app/modules/tmr.c old mode 100644 new mode 100755 index 65007778..8e9bc852 --- a/app/modules/tmr.c +++ b/app/modules/tmr.c @@ -1,232 +1,358 @@ -// 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 interval 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 clean 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.interval(id, interval) + set alarm interval, running alarm will be restarted +tmr.state(id) + ret: (bool, int) or nil + returns alarm status (true=started/false=stopped) and mode + nil if timer is unregistered +tmr.softwd(int) + set a negative value to stop the timer + any other value starts the timer, when the + countdown reaches zero, the device restarts + the timer units are seconds +*/ + +#define MIN_OPT_LEVEL 2 -//#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "platform.h" #include "auxmods.h" #include "lrotable.h" - +#include "lrodefs.h" #include "c_types.h" -static os_timer_t alarm_timer[NUM_TMR]; -static int alarm_timer_cb_ref[NUM_TMR] = {LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF}; -static bool alarm_timer_repeat[NUM_TMR]= {0,0,0,0,0,0,0}; +#define TIMER_MODE_OFF 3 +#define TIMER_MODE_SINGLE 0 +#define TIMER_MODE_SEMI 2 +#define TIMER_MODE_AUTO 1 +#define TIMER_IDLE_FLAG (1<<7) -void alarm_timer_common(lua_State* L, unsigned id){ - if(alarm_timer_cb_ref[id] == LUA_NOREF) - return; - lua_rawgeti(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); - if(alarm_timer_repeat[id]==0) - { - if(alarm_timer_cb_ref[id] != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); +//well, the following are my assumptions +//why, oh why is there no good documentation +//chinese companies should learn from Atmel +extern void ets_timer_arm_new(os_timer_t* t, uint32_t milliseconds, uint32_t repeat_flag, uint32_t isMstimer); +extern void ets_timer_disarm(os_timer_t* t); +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(); +extern uint32_t platform_tmr_exists(uint32_t t); +extern uint32_t system_rtc_clock_cali_proc(); +extern uint32_t system_get_rtc_time(); +extern void system_restart(); - } - lua_call(L, 0, 0); +//in fact lua_State is constant, it's pointless to pass it around +//but hey, whatever, I'll just pass it, still we waste 28B here +typedef struct{ + os_timer_t os; + lua_State* L; + sint32_t lua_ref; + uint32_t interval; + uint8_t mode; +}timer_struct_t; +typedef timer_struct_t* timer_t; + +//everybody just love unions! riiiiight? +static union { + uint64_t block; + uint32_t part[2]; +} rtc_time; +static sint32_t soft_watchdog = -1; +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]; + if(tmr->lua_ref == LUA_NOREF || tmr->L == NULL) + return; + lua_rawgeti(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref); + //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); + tmr->lua_ref = LUA_NOREF; + tmr->mode = TIMER_MODE_OFF; + }else if(tmr->mode == TIMER_MODE_SEMI){ + tmr->mode |= TIMER_IDLE_FLAG; + } + lua_call(tmr->L, 0, 0); } -void alarm_timer_cb0(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 0); +// Lua: tmr.delay( us ) +static int tmr_delay( lua_State* L ){ + sint32_t us = luaL_checkinteger(L, 1); + if(us <= 0) + return luaL_error(L, "wrong arg range"); + while(us >= 1000000){ + us -= 1000000; + os_delay_us(1000000); + WRITE_PERI_REG(0x60000914, 0x73); + } + if(us>0){ + os_delay_us(us); + WRITE_PERI_REG(0x60000914, 0x73); + } + return 0; } -void alarm_timer_cb1(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 1); +// Lua: tmr.now() , return system timer in us +static int tmr_now(lua_State* L){ + uint32_t now = 0x7FFFFFFF & system_get_time(); + lua_pushinteger(L, now); + return 1; } -void alarm_timer_cb2(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 2); +// Lua: tmr.register( id, interval, mode, function ) +static int tmr_register(lua_State* L){ + uint32_t id = luaL_checkinteger(L, 1); + MOD_CHECK_ID(tmr, id); + sint32_t interval = luaL_checkinteger(L, 2); + uint8_t mode = luaL_checkinteger(L, 3); + //validate arguments + uint8_t args_valid = interval <= 0 + || (mode != TIMER_MODE_SINGLE && mode != TIMER_MODE_SEMI && mode != TIMER_MODE_AUTO) + || (lua_type(L, 4) != LUA_TFUNCTION && lua_type(L, 4) != LUA_TLIGHTFUNCTION); + if(args_valid) + return luaL_error(L, "wrong arg range"); + //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 + if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref) + luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref); + tmr->lua_ref = ref; + tmr->mode = mode|TIMER_IDLE_FLAG; + tmr->interval = interval; + tmr->L = L; + ets_timer_setfn(&tmr->os, alarm_timer_common, (void*)id); + return 0; } -void alarm_timer_cb3(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 3); +// Lua: tmr.start( id ) +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]; + //we return false if the timer is not idle + if(!(tmr->mode&TIMER_IDLE_FLAG)){ + lua_pushboolean(L, 0); + }else{ + tmr->mode &= ~TIMER_IDLE_FLAG; + ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1); + lua_pushboolean(L, 1); + } + return 1; } -void alarm_timer_cb4(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 4); +// Lua: tmr.alarm( id, interval, repeat, function ) +static int tmr_alarm(lua_State* L){ + tmr_register(L); + return tmr_start(L); } -void alarm_timer_cb5(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 5); +// Lua: tmr.stop( id ) +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]; + //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; + ets_timer_disarm(&tmr->os); + lua_pushboolean(L, 1); + }else{ + lua_pushboolean(L, 0); + } + return 1; } -void alarm_timer_cb6(void *arg){ - if( !arg ) - return; - alarm_timer_common((lua_State*)arg, 6); +// 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; } -typedef void (*alarm_timer_callback)(void *arg); -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}; - -// Lua: delay( us ) -static int tmr_delay( lua_State* L ) -{ - s32 us; - us = luaL_checkinteger( L, 1 ); - if ( us <= 0 ) - return luaL_error( L, "wrong arg range" ); - if(us<1000000) - { - os_delay_us( us ); - WRITE_PERI_REG(0x60000914, 0x73); - return 0; - } - unsigned sec = (unsigned)us / 1000000; - unsigned remain = (unsigned)us % 1000000; - int i = 0; - for(i=0;i0) - os_delay_us( remain ); - return 0; +// Lua: tmr.interval( id, 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]; + sint32_t interval = luaL_checkinteger(L, 2); + if(interval <= 0) + return luaL_error(L, "wrong arg range"); + if(tmr->mode != TIMER_MODE_OFF){ + tmr->interval = interval; + if(!(tmr->mode&TIMER_IDLE_FLAG)){ + ets_timer_disarm(&tmr->os); + ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1); + } + } + return 0; } -// Lua: now() , return system timer in us -static int tmr_now( lua_State* L ) -{ - unsigned now = 0x7FFFFFFF & system_get_time(); - lua_pushinteger( L, now ); - return 1; +// 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; } -// Lua: alarm( id, interval, repeat, function ) -static int tmr_alarm( lua_State* L ) -{ - s32 interval; - unsigned repeat = 0; - int stack = 1; - - unsigned id = luaL_checkinteger( L, stack ); - stack++; - MOD_CHECK_ID( tmr, id ); - - interval = luaL_checkinteger( L, stack ); - stack++; - if ( interval <= 0 ) - return luaL_error( L, "wrong arg range" ); - - if ( lua_isnumber(L, stack) ){ - repeat = lua_tointeger(L, stack); - stack++; - if ( repeat != 1 && repeat != 0 ) - return luaL_error( L, "wrong arg type" ); - alarm_timer_repeat[id]=repeat; - } - - // luaL_checkanyfunction(L, stack); - 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 - 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); - } - - os_timer_disarm(&(alarm_timer[id])); - 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: stop( id ) -static int tmr_stop( lua_State* L ) -{ - unsigned id = luaL_checkinteger( L, 1 ); - MOD_CHECK_ID( tmr, id ); - - os_timer_disarm(&(alarm_timer[id])); - if(alarm_timer_cb_ref[id] != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]); - - return 0; -} +/*I left the led comments 'couse I don't know +why they are here*/ // extern void update_key_led(); -// Lua: wdclr() -static int tmr_wdclr( lua_State* L ) -{ - WRITE_PERI_REG(0x60000914, 0x73); - // update_key_led(); - return 0; +// Lua: tmr.wdclr() +static int tmr_wdclr( lua_State* L ){ + WRITE_PERI_REG(0x60000914, 0x73); + // update_key_led(); + return 0; } -static os_timer_t rtc_timer_updator; -static uint32_t cur_count = 0; -static uint32_t rtc_10ms = 0; -void rtc_timer_update_cb(void *arg){ - uint32_t t = (uint32_t)system_get_rtc_time(); - uint32_t delta = 0; - if(t>=cur_count){ - delta = t-cur_count; - }else{ - delta = 0xFFFFFFF - cur_count + t + 1; - } - // uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count); - // NODE_ERR("%x\n",t); - cur_count = t; - uint32_t c = system_rtc_clock_cali_proc(); - uint32_t itg = c >> 12; // ~=5 - uint32_t dec = c & 0xFFF; // ~=2ff - rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000; - // TODO: store rtc_10ms to rtc memory. +//system_rtc_clock_cali_proc() returns +//a fixed point value (12 bit fraction part) +//it tells how many rtc clock ticks represent 1us. +//the high 64 bits of the uint64_t multiplication +//are unnedded (I did the math) +static uint32_t rtc2sec(uint64_t rtc){ + uint64_t aku = system_rtc_clock_cali_proc(); + aku *= rtc; + return (aku>>12)/1000000; } -// Lua: time() , return rtc time in second -static int tmr_time( lua_State* L ) -{ - uint32_t local = rtc_10ms; - lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF ); - return 1; + +//the following function workes, I just wrote it and didn't use it. +/*static uint64_t sec2rtc(uint32_t sec){ + uint64_t aku = (1<<20)/system_rtc_clock_cali_proc(); + aku *= sec; + return (aku>>8)*1000000; +}*/ + +inline static void rtc_timer_update(){ + uint32_t current = system_get_rtc_time(); + if(rtc_time.part[0] > current) //overflow check + rtc_time.part[1]++; + rtc_time.part[0] = current; +} + +void rtc_callback(void *arg){ + 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 -#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 ) }, + { LSTRKEY( "interval" ), LFUNCVAL ( tmr_interval) }, +#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 - { LNILKEY, LNILVAL } + { LNILKEY, LNILVAL } }; -LUALIB_API int luaopen_tmr( lua_State *L ) -{ - int i = 0; - for(i=0;i 0 - return 0; -#else // #if LUA_OPTIMIZE_MEMORY > 0 - luaL_register( L, AUXLIB_TMR, tmr_map ); - // Add constants - - return 1; -#endif // #if LUA_OPTIMIZE_MEMORY > 0 + return 0; +#else + luaL_register( L, AUXLIB_TMR, tmr_map ); + lua_pushvalue( L, -1 ); + lua_setmetatable( L, -2 ); + MOD_REG_NUMBER( L, "ALARM_SINGLE", TIMER_MODE_SINGLE ); + MOD_REG_NUMBER( L, "ALARM_SEMI", TIMER_MODE_SEMI ); + MOD_REG_NUMBER( L, "ALARM_AUTO", TIMER_MODE_AUTO ); + return 1; +#endif } +