tmr.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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. #include "user_interface.h"
  52. #include "swTimer/swTimer.h"
  53. #define TIMER_MODE_OFF 3
  54. #define TIMER_MODE_SINGLE 0
  55. #define TIMER_MODE_SEMI 2
  56. #define TIMER_MODE_AUTO 1
  57. #define TIMER_IDLE_FLAG (1<<7)
  58. #define STRINGIFY_VAL(x) #x
  59. #define STRINGIFY(x) STRINGIFY_VAL(x)
  60. // assuming system_timer_reinit() has *not* been called
  61. #define MAX_TIMEOUT_DEF 6870947 //SDK 1.5.3 limit (0x68D7A3)
  62. static const uint32 MAX_TIMEOUT=MAX_TIMEOUT_DEF;
  63. static const char* MAX_TIMEOUT_ERR_STR = "Range: 1-"STRINGIFY(MAX_TIMEOUT_DEF);
  64. typedef struct{
  65. os_timer_t os;
  66. sint32_t lua_ref, self_ref;
  67. uint32_t interval;
  68. uint8_t mode;
  69. }timer_struct_t;
  70. typedef timer_struct_t* timer_t;
  71. // The previous implementation extended the rtc counter to 64 bits, and then
  72. // applied rtc2sec with the current calibration value to that 64 bit value.
  73. // This means that *ALL* clock ticks since bootup are counted with the *current*
  74. // clock period. In extreme cases (long uptime, sudden temperature change), this
  75. // could result in tmr.time() going backwards....
  76. // This implementation instead applies rtc2usec to short time intervals only (the
  77. // longest being around 1 second), and then accumulates the resulting microseconds
  78. // in a 64 bit counter. That's guaranteed to be monotonic, and should be a lot closer
  79. // to representing an actual uptime.
  80. static uint32_t rtc_time_cali=0;
  81. static uint32_t last_rtc_time=0;
  82. static uint64_t last_rtc_time_us=0;
  83. static sint32_t soft_watchdog = -1;
  84. static timer_struct_t alarm_timers[NUM_TMR];
  85. static os_timer_t rtc_timer;
  86. static void alarm_timer_common(void* arg){
  87. timer_t tmr = (timer_t)arg;
  88. lua_State* L = lua_getstate();
  89. if(tmr->lua_ref == LUA_NOREF)
  90. return;
  91. lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  92. if (tmr->self_ref == LUA_REFNIL) {
  93. uint32_t id = tmr - alarm_timers;
  94. lua_pushinteger(L, id);
  95. } else {
  96. lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
  97. }
  98. //if the timer was set to single run we clean up after it
  99. if(tmr->mode == TIMER_MODE_SINGLE){
  100. luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  101. tmr->lua_ref = LUA_NOREF;
  102. tmr->mode = TIMER_MODE_OFF;
  103. }else if(tmr->mode == TIMER_MODE_SEMI){
  104. tmr->mode |= TIMER_IDLE_FLAG;
  105. }
  106. if (tmr->mode != TIMER_MODE_AUTO && tmr->self_ref != LUA_REFNIL) {
  107. luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
  108. tmr->self_ref = LUA_NOREF;
  109. }
  110. lua_call(L, 1, 0);
  111. }
  112. // Lua: tmr.delay( us )
  113. static int tmr_delay( lua_State* L ){
  114. sint32_t us = luaL_checkinteger(L, 1);
  115. if(us <= 0)
  116. return luaL_error(L, "wrong arg range");
  117. while(us >= 10000){
  118. us -= 10000;
  119. os_delay_us(10000);
  120. system_soft_wdt_feed ();
  121. }
  122. if(us>0){
  123. os_delay_us(us);
  124. system_soft_wdt_feed ();
  125. }
  126. return 0;
  127. }
  128. // Lua: tmr.now() , return system timer in us
  129. static int tmr_now(lua_State* L){
  130. uint32_t now = 0x7FFFFFFF & system_get_time();
  131. lua_pushinteger(L, now);
  132. return 1;
  133. }
  134. static timer_t tmr_get( lua_State *L, int stack ) {
  135. // Deprecated: static 0-6 timers control by index.
  136. luaL_argcheck(L, (lua_isuserdata(L, stack) || lua_isnumber(L, stack)), 1, "timer object or numerical ID expected");
  137. if (lua_isuserdata(L, stack)) {
  138. return (timer_t)luaL_checkudata(L, stack, "tmr.timer");
  139. } else {
  140. uint32_t id = luaL_checkinteger(L, 1);
  141. luaL_argcheck(L, platform_tmr_exists(id), 1, "invalid timer index");
  142. return &alarm_timers[id];
  143. }
  144. return 0;
  145. }
  146. // Lua: tmr.register( id / ref, interval, mode, function )
  147. static int tmr_register(lua_State* L){
  148. timer_t tmr = tmr_get(L, 1);
  149. uint32_t interval = luaL_checkinteger(L, 2);
  150. uint8_t mode = luaL_checkinteger(L, 3);
  151. luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
  152. luaL_argcheck(L, (mode == TIMER_MODE_SINGLE || mode == TIMER_MODE_SEMI || mode == TIMER_MODE_AUTO), 3, "Invalid mode");
  153. luaL_argcheck(L, (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION), 4, "Must be function");
  154. //get the lua function reference
  155. lua_pushvalue(L, 4);
  156. sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
  157. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  158. os_timer_disarm(&tmr->os);
  159. //there was a bug in this part, the second part of the following condition was missing
  160. if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
  161. luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  162. tmr->lua_ref = ref;
  163. tmr->mode = mode|TIMER_IDLE_FLAG;
  164. tmr->interval = interval;
  165. os_timer_setfn(&tmr->os, alarm_timer_common, tmr);
  166. return 0;
  167. }
  168. // Lua: tmr.start( id / ref )
  169. static int tmr_start(lua_State* L){
  170. timer_t tmr = tmr_get(L, 1);
  171. if (tmr->self_ref == LUA_NOREF) {
  172. lua_pushvalue(L, 1);
  173. tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  174. }
  175. //we return false if the timer is not idle
  176. if(!(tmr->mode&TIMER_IDLE_FLAG)){
  177. lua_pushboolean(L, 0);
  178. }else{
  179. tmr->mode &= ~TIMER_IDLE_FLAG;
  180. os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
  181. lua_pushboolean(L, 1);
  182. }
  183. return 1;
  184. }
  185. // Lua: tmr.alarm( id / ref, interval, repeat, function )
  186. static int tmr_alarm(lua_State* L){
  187. tmr_register(L);
  188. return tmr_start(L);
  189. }
  190. // Lua: tmr.stop( id / ref )
  191. static int tmr_stop(lua_State* L){
  192. timer_t tmr = tmr_get(L, 1);
  193. if (tmr->self_ref != LUA_REFNIL) {
  194. luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
  195. tmr->self_ref = LUA_NOREF;
  196. }
  197. //we return false if the timer is idle (of not registered)
  198. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
  199. tmr->mode |= TIMER_IDLE_FLAG;
  200. os_timer_disarm(&tmr->os);
  201. lua_pushboolean(L, 1);
  202. }else{
  203. lua_pushboolean(L, 0);
  204. }
  205. return 1;
  206. }
  207. #ifdef ENABLE_TIMER_SUSPEND
  208. static int tmr_suspend(lua_State* L){
  209. timer_t tmr = tmr_get(L, 1);
  210. if((tmr->mode & TIMER_IDLE_FLAG) == 1){
  211. return luaL_error(L, "timer not armed");
  212. }
  213. int retval = swtmr_suspend(&tmr->os);
  214. if(retval != SWTMR_OK){
  215. return luaL_error(L, swtmr_errorcode2str(retval));
  216. }
  217. else{
  218. lua_pushboolean(L, true);
  219. }
  220. return 1;
  221. }
  222. static int tmr_resume(lua_State* L){
  223. timer_t tmr = tmr_get(L, 1);
  224. if(swtmr_suspended_test(&tmr->os) == FALSE){
  225. return luaL_error(L, "timer not suspended");
  226. }
  227. int retval = swtmr_resume(&tmr->os);
  228. if(retval != SWTMR_OK){
  229. return luaL_error(L, swtmr_errorcode2str(retval));
  230. }
  231. else{
  232. lua_pushboolean(L, true);
  233. }
  234. return 1;
  235. }
  236. static int tmr_suspend_all (lua_State *L)
  237. {
  238. sint32 retval = swtmr_suspend(NULL);
  239. // lua_pushnumber(L, swtmr_suspend(NULL));
  240. if(retval!=SWTMR_OK){
  241. return luaL_error(L, swtmr_errorcode2str(retval));
  242. }
  243. else{
  244. lua_pushboolean(L, true);
  245. }
  246. return 1;
  247. }
  248. static int tmr_resume_all (lua_State *L)
  249. {
  250. sint32 retval = swtmr_resume(NULL);
  251. if(retval!=SWTMR_OK){
  252. return luaL_error(L, swtmr_errorcode2str(retval));
  253. }
  254. else{
  255. lua_pushboolean(L, true);
  256. }
  257. return 1;
  258. }
  259. #endif
  260. // Lua: tmr.unregister( id / ref )
  261. static int tmr_unregister(lua_State* L){
  262. timer_t tmr = tmr_get(L, 1);
  263. if (tmr->self_ref != LUA_REFNIL) {
  264. luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
  265. tmr->self_ref = LUA_NOREF;
  266. }
  267. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  268. os_timer_disarm(&tmr->os);
  269. if(tmr->lua_ref != LUA_NOREF)
  270. luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  271. tmr->lua_ref = LUA_NOREF;
  272. tmr->mode = TIMER_MODE_OFF;
  273. return 0;
  274. }
  275. // Lua: tmr.interval( id / ref, interval )
  276. static int tmr_interval(lua_State* L){
  277. timer_t tmr = tmr_get(L, 1);
  278. uint32_t interval = luaL_checkinteger(L, 2);
  279. luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
  280. if(tmr->mode != TIMER_MODE_OFF){
  281. tmr->interval = interval;
  282. if(!(tmr->mode&TIMER_IDLE_FLAG)){
  283. os_timer_disarm(&tmr->os);
  284. os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
  285. }
  286. }
  287. return 0;
  288. }
  289. // Lua: tmr.state( id / ref )
  290. static int tmr_state(lua_State* L){
  291. timer_t tmr = tmr_get(L, 1);
  292. if(tmr->mode == TIMER_MODE_OFF){
  293. lua_pushnil(L);
  294. return 1;
  295. }
  296. lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
  297. lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG));
  298. #ifdef ENABLE_TIMER_SUSPEND
  299. lua_pushboolean(L, swtmr_suspended_test(&tmr->os));
  300. #else
  301. lua_pushnil(L);
  302. #endif
  303. return 3;
  304. }
  305. /*I left the led comments 'couse I don't know
  306. why they are here*/
  307. // extern void update_key_led();
  308. // Lua: tmr.wdclr()
  309. static int tmr_wdclr( lua_State* L ){
  310. system_soft_wdt_feed ();
  311. // update_key_led();
  312. return 0;
  313. }
  314. //system_rtc_clock_cali_proc() returns
  315. //a fixed point value (12 bit fraction part)
  316. //it tells how many rtc clock ticks represent 1us.
  317. //the high 64 bits of the uint64_t multiplication
  318. //are unnedded (I did the math)
  319. static uint32_t rtc2usec(uint64_t rtc){
  320. return (rtc*rtc_time_cali)>>12;
  321. }
  322. // This returns the number of microseconds uptime. Note that it relies on the rtc clock,
  323. // which is notoriously temperature dependent
  324. inline static uint64_t rtc_timer_update(bool do_calibration){
  325. if (do_calibration || rtc_time_cali==0)
  326. rtc_time_cali=system_rtc_clock_cali_proc();
  327. uint32_t current = system_get_rtc_time();
  328. uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound
  329. uint32_t us_since_last=rtc2usec(since_last);
  330. uint64_t now=last_rtc_time_us+us_since_last;
  331. // Only update if at least 100ms has passed since we last updated.
  332. // This prevents the rounding errors in rtc2usec from accumulating
  333. if (us_since_last>=100000)
  334. {
  335. last_rtc_time=current;
  336. last_rtc_time_us=now;
  337. }
  338. return now;
  339. }
  340. void rtc_callback(void *arg){
  341. rtc_timer_update(true);
  342. if(soft_watchdog > 0){
  343. soft_watchdog--;
  344. if(soft_watchdog == 0)
  345. system_restart();
  346. }
  347. }
  348. // Lua: tmr.time() , return rtc time in second
  349. static int tmr_time( lua_State* L ){
  350. uint64_t us=rtc_timer_update(false);
  351. lua_pushinteger(L, us/1000000);
  352. return 1;
  353. }
  354. // Lua: tmr.softwd( value )
  355. static int tmr_softwd( lua_State* L ){
  356. soft_watchdog = luaL_checkinteger(L, 1);
  357. return 0;
  358. }
  359. // Lua: tmr.create()
  360. static int tmr_create( lua_State *L ) {
  361. timer_t ud = (timer_t)lua_newuserdata(L, sizeof(timer_struct_t));
  362. if (!ud) return luaL_error(L, "not enough memory");
  363. luaL_getmetatable(L, "tmr.timer");
  364. lua_setmetatable(L, -2);
  365. ud->lua_ref = LUA_NOREF;
  366. ud->self_ref = LUA_NOREF;
  367. ud->mode = TIMER_MODE_OFF;
  368. os_timer_disarm(&ud->os);
  369. return 1;
  370. }
  371. #if defined(SWTMR_DEBUG)
  372. static void tmr_printRegistry(lua_State* L){
  373. swtmr_print_registry();
  374. }
  375. static void tmr_printSuspended(lua_State* L){
  376. swtmr_print_suspended();
  377. }
  378. static void tmr_printTimerlist(lua_State* L){
  379. swtmr_print_timer_list();
  380. }
  381. #endif
  382. // Module function map
  383. static const LUA_REG_TYPE tmr_dyn_map[] = {
  384. { LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
  385. { LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
  386. { LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
  387. { LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
  388. { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
  389. { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
  390. { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval) },
  391. #ifdef ENABLE_TIMER_SUSPEND
  392. { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
  393. { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
  394. #endif
  395. { LSTRKEY( "__gc" ), LFUNCVAL( tmr_unregister ) },
  396. { LSTRKEY( "__index" ), LROVAL( tmr_dyn_map ) },
  397. { LNILKEY, LNILVAL }
  398. };
  399. #if defined(SWTMR_DEBUG)
  400. static const LUA_REG_TYPE tmr_dbg_map[] = {
  401. { LSTRKEY( "printRegistry" ), LFUNCVAL( tmr_printRegistry ) },
  402. { LSTRKEY( "printSuspended" ), LFUNCVAL( tmr_printSuspended ) },
  403. { LSTRKEY( "printTimerlist" ), LFUNCVAL( tmr_printTimerlist ) },
  404. { LNILKEY, LNILVAL }
  405. };
  406. #endif
  407. static const LUA_REG_TYPE tmr_map[] = {
  408. { LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
  409. { LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
  410. { LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
  411. { LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) },
  412. { LSTRKEY( "time" ), LFUNCVAL( tmr_time ) },
  413. { LSTRKEY( "register" ), LFUNCVAL( tmr_register ) },
  414. { LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
  415. { LSTRKEY( "start" ), LFUNCVAL( tmr_start ) },
  416. { LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
  417. #ifdef ENABLE_TIMER_SUSPEND
  418. { LSTRKEY( "suspend" ), LFUNCVAL( tmr_suspend ) },
  419. { LSTRKEY( "suspend_all" ), LFUNCVAL( tmr_suspend_all ) },
  420. { LSTRKEY( "resume" ), LFUNCVAL( tmr_resume ) },
  421. { LSTRKEY( "resume_all" ), LFUNCVAL( tmr_resume_all ) },
  422. #endif
  423. { LSTRKEY( "unregister" ), LFUNCVAL( tmr_unregister ) },
  424. { LSTRKEY( "state" ), LFUNCVAL( tmr_state ) },
  425. { LSTRKEY( "interval" ), LFUNCVAL( tmr_interval ) },
  426. { LSTRKEY( "create" ), LFUNCVAL( tmr_create ) },
  427. #if defined(SWTMR_DEBUG)
  428. { LSTRKEY( "debug" ), LROVAL( tmr_dbg_map ) },
  429. #endif
  430. { LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
  431. { LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
  432. { LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
  433. { LNILKEY, LNILVAL }
  434. };
  435. int luaopen_tmr( lua_State *L ){
  436. int i;
  437. luaL_rometatable(L, "tmr.timer", (void *)tmr_dyn_map);
  438. for(i=0; i<NUM_TMR; i++){
  439. alarm_timers[i].lua_ref = LUA_NOREF;
  440. alarm_timers[i].self_ref = LUA_REFNIL;
  441. alarm_timers[i].mode = TIMER_MODE_OFF;
  442. //improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call.
  443. ets_timer_disarm(&alarm_timers[i].os);
  444. }
  445. last_rtc_time=system_get_rtc_time(); // Right now is time 0
  446. last_rtc_time_us=0;
  447. //improve boot speed by using ets_timer_disarm instead of os_timer_disarm to avoid timer registry maintenance call.
  448. ets_timer_disarm(&rtc_timer);
  449. os_timer_setfn(&rtc_timer, rtc_callback, NULL);
  450. os_timer_arm(&rtc_timer, 1000, 1);
  451. return 0;
  452. }
  453. NODEMCU_MODULE(TMR, "tmr", tmr_map, luaopen_tmr);