tmr.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*guys, srsly, turn on warnings in the makefile*/
  2. #if defined(__GNUC__)
  3. #pragma GCC diagnostic warning "-Wall"
  4. #pragma GCC diagnostic warning "-Wextra"
  5. #pragma GCC diagnostic ignored "-Wunused-parameter"
  6. #endif
  7. /*-------------------------------------
  8. NEW TIMER API
  9. ---------------------------------------
  10. tmr.wdclr() -- not changed
  11. tmr.now() -- not changed
  12. tmr.time() -- not changed
  13. tmr.delay() -- not changed
  14. tmr.alarm() -- not changed
  15. tmr.stop() -- changed, see below. use tmr.unregister for old functionality
  16. tmr.register(id, interval, mode, function)
  17. bind function with timer and set the interval in ms
  18. the mode can be:
  19. tmr.ALARM_SINGLE for a single run alarm
  20. tmr.ALARM_SEMI for a multiple single run alarm
  21. tmr.ALARM_AUTO for a repating alarm
  22. tmr.register does NOT start the timer
  23. tmr.alarm is a tmr.register & tmr.start macro
  24. tmr.unregister(id)
  25. stop alarm, unbind function and clean up memory
  26. not needed for ALARM_SINGLE, as it unregisters itself
  27. tmr.start(id)
  28. ret: bool
  29. start a alarm, returns true on success
  30. tmr.stop(id)
  31. ret: bool
  32. stops a alarm, returns true on success
  33. this call dose not free any memory, to do so use tmr.unregister
  34. stopped alarms can be started with start
  35. tmr.interval(id, interval)
  36. set alarm interval, running alarm will be restarted
  37. tmr.state(id)
  38. ret: (bool, int) or nil
  39. returns alarm status (true=started/false=stopped) and mode
  40. nil if timer is unregistered
  41. tmr.softwd(int)
  42. set a negative value to stop the timer
  43. any other value starts the timer, when the
  44. countdown reaches zero, the device restarts
  45. the timer units are seconds
  46. */
  47. #include "module.h"
  48. #include "lauxlib.h"
  49. #include "platform.h"
  50. #include "c_types.h"
  51. #define TIMER_MODE_OFF 3
  52. #define TIMER_MODE_SINGLE 0
  53. #define TIMER_MODE_SEMI 2
  54. #define TIMER_MODE_AUTO 1
  55. #define TIMER_IDLE_FLAG (1<<7)
  56. //in fact lua_State is constant, it's pointless to pass it around
  57. //but hey, whatever, I'll just pass it, still we waste 28B here
  58. typedef struct{
  59. os_timer_t os;
  60. lua_State* L;
  61. sint32_t lua_ref;
  62. uint32_t interval;
  63. uint8_t mode;
  64. }timer_struct_t;
  65. typedef timer_struct_t* timer_t;
  66. //everybody just love unions! riiiiight?
  67. static union {
  68. uint64_t block;
  69. uint32_t part[2];
  70. } rtc_time;
  71. static sint32_t soft_watchdog = -1;
  72. static timer_struct_t alarm_timers[NUM_TMR];
  73. static os_timer_t rtc_timer;
  74. static void alarm_timer_common(void* arg){
  75. timer_t tmr = &alarm_timers[(uint32_t)arg];
  76. if(tmr->lua_ref == LUA_NOREF || tmr->L == NULL)
  77. return;
  78. lua_rawgeti(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
  79. //if the timer was set to single run we clean up after it
  80. if(tmr->mode == TIMER_MODE_SINGLE){
  81. luaL_unref(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
  82. tmr->lua_ref = LUA_NOREF;
  83. tmr->mode = TIMER_MODE_OFF;
  84. }else if(tmr->mode == TIMER_MODE_SEMI){
  85. tmr->mode |= TIMER_IDLE_FLAG;
  86. }
  87. lua_call(tmr->L, 0, 0);
  88. }
  89. // Lua: tmr.delay( us )
  90. static int tmr_delay( lua_State* L ){
  91. sint32_t us = luaL_checkinteger(L, 1);
  92. if(us <= 0)
  93. return luaL_error(L, "wrong arg range");
  94. while(us >= 1000000){
  95. us -= 1000000;
  96. os_delay_us(1000000);
  97. system_soft_wdt_feed ();
  98. }
  99. if(us>0){
  100. os_delay_us(us);
  101. system_soft_wdt_feed ();
  102. }
  103. return 0;
  104. }
  105. // Lua: tmr.now() , return system timer in us
  106. static int tmr_now(lua_State* L){
  107. uint32_t now = 0x7FFFFFFF & system_get_time();
  108. lua_pushinteger(L, now);
  109. return 1;
  110. }
  111. // Lua: tmr.register( id, interval, mode, function )
  112. static int tmr_register(lua_State* L){
  113. uint32_t id = luaL_checkinteger(L, 1);
  114. MOD_CHECK_ID(tmr, id);
  115. sint32_t interval = luaL_checkinteger(L, 2);
  116. uint8_t mode = luaL_checkinteger(L, 3);
  117. //validate arguments
  118. const int32_t MAX_TIMEOUT = 0xC49BA5; // assuming system_timer_reinit() has *not* been called
  119. uint8_t args_invalid = (interval <= 0 || interval > MAX_TIMEOUT)
  120. || (mode != TIMER_MODE_SINGLE && mode != TIMER_MODE_SEMI && mode != TIMER_MODE_AUTO)
  121. || (lua_type(L, 4) != LUA_TFUNCTION && lua_type(L, 4) != LUA_TLIGHTFUNCTION);
  122. if(args_invalid)
  123. return luaL_error(L, "wrong arg range");
  124. //get the lua function reference
  125. lua_pushvalue(L, 4);
  126. sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
  127. timer_t tmr = &alarm_timers[id];
  128. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  129. ets_timer_disarm(&tmr->os);
  130. //there was a bug in this part, the second part of the following condition was missing
  131. if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
  132. luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  133. tmr->lua_ref = ref;
  134. tmr->mode = mode|TIMER_IDLE_FLAG;
  135. tmr->interval = interval;
  136. tmr->L = L;
  137. ets_timer_setfn(&tmr->os, alarm_timer_common, (void*)id);
  138. return 0;
  139. }
  140. // Lua: tmr.start( id )
  141. static int tmr_start(lua_State* L){
  142. uint8_t id = luaL_checkinteger(L, 1);
  143. MOD_CHECK_ID(tmr,id);
  144. timer_t tmr = &alarm_timers[id];
  145. //we return false if the timer is not idle
  146. if(!(tmr->mode&TIMER_IDLE_FLAG)){
  147. lua_pushboolean(L, 0);
  148. }else{
  149. tmr->mode &= ~TIMER_IDLE_FLAG;
  150. ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
  151. lua_pushboolean(L, 1);
  152. }
  153. return 1;
  154. }
  155. // Lua: tmr.alarm( id, interval, repeat, function )
  156. static int tmr_alarm(lua_State* L){
  157. tmr_register(L);
  158. return tmr_start(L);
  159. }
  160. // Lua: tmr.stop( id )
  161. static int tmr_stop(lua_State* L){
  162. uint8_t id = luaL_checkinteger(L, 1);
  163. MOD_CHECK_ID(tmr,id);
  164. timer_t tmr = &alarm_timers[id];
  165. //we return false if the timer is idle (of not registered)
  166. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
  167. tmr->mode |= TIMER_IDLE_FLAG;
  168. ets_timer_disarm(&tmr->os);
  169. lua_pushboolean(L, 1);
  170. }else{
  171. lua_pushboolean(L, 0);
  172. }
  173. return 1;
  174. }
  175. // Lua: tmr.unregister( id )
  176. static int tmr_unregister(lua_State* L){
  177. uint8_t id = luaL_checkinteger(L, 1);
  178. MOD_CHECK_ID(tmr,id);
  179. timer_t tmr = &alarm_timers[id];
  180. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  181. ets_timer_disarm(&tmr->os);
  182. if(tmr->lua_ref != LUA_NOREF)
  183. luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  184. tmr->lua_ref = LUA_NOREF;
  185. tmr->mode = TIMER_MODE_OFF;
  186. return 0;
  187. }
  188. // Lua: tmr.interval( id, interval )
  189. static int tmr_interval(lua_State* L){
  190. uint8_t id = luaL_checkinteger(L, 1);
  191. MOD_CHECK_ID(tmr,id);
  192. timer_t tmr = &alarm_timers[id];
  193. sint32_t interval = luaL_checkinteger(L, 2);
  194. if(interval <= 0)
  195. return luaL_error(L, "wrong arg range");
  196. if(tmr->mode != TIMER_MODE_OFF){
  197. tmr->interval = interval;
  198. if(!(tmr->mode&TIMER_IDLE_FLAG)){
  199. ets_timer_disarm(&tmr->os);
  200. ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
  201. }
  202. }
  203. return 0;
  204. }
  205. // Lua: tmr.state( id )
  206. static int tmr_state(lua_State* L){
  207. uint8_t id = luaL_checkinteger(L, 1);
  208. MOD_CHECK_ID(tmr,id);
  209. timer_t tmr = &alarm_timers[id];
  210. if(tmr->mode == TIMER_MODE_OFF){
  211. lua_pushnil(L);
  212. return 1;
  213. }
  214. lua_pushboolean(L, (tmr->mode&TIMER_IDLE_FLAG)==0);
  215. lua_pushinteger(L, tmr->mode&(~TIMER_IDLE_FLAG));
  216. return 2;
  217. }
  218. /*I left the led comments 'couse I don't know
  219. why they are here*/
  220. // extern void update_key_led();
  221. // Lua: tmr.wdclr()
  222. static int tmr_wdclr( lua_State* L ){
  223. system_soft_wdt_feed ();
  224. // update_key_led();
  225. return 0;
  226. }
  227. //system_rtc_clock_cali_proc() returns
  228. //a fixed point value (12 bit fraction part)
  229. //it tells how many rtc clock ticks represent 1us.
  230. //the high 64 bits of the uint64_t multiplication
  231. //are unnedded (I did the math)
  232. static uint32_t rtc2sec(uint64_t rtc){
  233. uint64_t aku = system_rtc_clock_cali_proc();
  234. aku *= rtc;
  235. return (aku>>12)/1000000;
  236. }
  237. //the following function workes, I just wrote it and didn't use it.
  238. /*static uint64_t sec2rtc(uint32_t sec){
  239. uint64_t aku = (1<<20)/system_rtc_clock_cali_proc();
  240. aku *= sec;
  241. return (aku>>8)*1000000;
  242. }*/
  243. inline static void rtc_timer_update(){
  244. uint32_t current = system_get_rtc_time();
  245. if(rtc_time.part[0] > current) //overflow check
  246. rtc_time.part[1]++;
  247. rtc_time.part[0] = current;
  248. }
  249. void rtc_callback(void *arg){
  250. rtc_timer_update();
  251. if(soft_watchdog > 0){
  252. soft_watchdog--;
  253. if(soft_watchdog == 0)
  254. system_restart();
  255. }
  256. }
  257. // Lua: tmr.time() , return rtc time in second
  258. static int tmr_time( lua_State* L ){
  259. rtc_timer_update();
  260. lua_pushinteger(L, rtc2sec(rtc_time.block));
  261. return 1;
  262. }
  263. // Lua: tmr.softwd( value )
  264. static int tmr_softwd( lua_State* L ){
  265. soft_watchdog = luaL_checkinteger(L, 1);
  266. return 0;
  267. }
  268. // Module function map
  269. static const LUA_REG_TYPE tmr_map[] = {
  270. { LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
  271. { LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
  272. { LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
  273. { LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) },
  274. { LSTRKEY( "time" ), LFUNCVAL( tmr_time ) },
  275. { LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
  276. { LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
  277. { LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
  278. { LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
  279. { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
  280. { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
  281. { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
  282. { LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
  283. { LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
  284. { LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
  285. { LNILKEY, LNILVAL }
  286. };
  287. int luaopen_tmr( lua_State *L ){
  288. int i;
  289. for(i=0; i<NUM_TMR; i++){
  290. alarm_timers[i].lua_ref = LUA_NOREF;
  291. alarm_timers[i].mode = TIMER_MODE_OFF;
  292. ets_timer_disarm(&alarm_timers[i].os);
  293. }
  294. rtc_time.block = 0;
  295. ets_timer_disarm(&rtc_timer);
  296. ets_timer_setfn(&rtc_timer, rtc_callback, NULL);
  297. ets_timer_arm_new(&rtc_timer, 1000, 1, 1);
  298. return 0;
  299. }
  300. NODEMCU_MODULE(TMR, "tmr", tmr_map, luaopen_tmr);