tmr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. /* See docs/modules/tmr.md for documentaiton o current API */
  8. #include "module.h"
  9. #include "lauxlib.h"
  10. #include "platform.h"
  11. #include <stdint.h>
  12. #include "user_interface.h"
  13. #include "pm/swtimer.h"
  14. #define TIMER_MODE_SINGLE 0
  15. #define TIMER_MODE_AUTO 1
  16. #define TIMER_MODE_SEMI 2
  17. #define TIMER_MODE_OFF 3
  18. #define TIMER_IDLE_FLAG (1<<7)
  19. #define STRINGIFY_VAL(x) #x
  20. #define STRINGIFY(x) STRINGIFY_VAL(x)
  21. // assuming system_timer_reinit() has *not* been called
  22. #define MAX_TIMEOUT_DEF 0x68D7A3 // SDK specfied limit
  23. static const uint32 MAX_TIMEOUT=MAX_TIMEOUT_DEF;
  24. static const char* MAX_TIMEOUT_ERR_STR = "Range: 1-"STRINGIFY(MAX_TIMEOUT_DEF);
  25. typedef struct{
  26. os_timer_t os;
  27. sint32_t lua_ref; /* Reference to registered callback function */
  28. sint32_t self_ref; /* Reference to UD registered slot */
  29. uint32_t interval;
  30. uint8_t mode;
  31. } tmr_t;
  32. // The previous implementation extended the rtc counter to 64 bits, and then
  33. // applied rtc2sec with the current calibration value to that 64 bit value.
  34. // This means that *ALL* clock ticks since bootup are counted with the
  35. // *current* clock period. In extreme cases (long uptime, sudden temperature
  36. // change), this could result in tmr.time() going backwards....
  37. //
  38. // This implementation instead applies rtc2usec to short time intervals only
  39. // (the longest being around 1 second), and then accumulates the resulting
  40. // microseconds in a 64 bit counter. That's guaranteed to be monotonic, and
  41. // should be a lot closer to representing an actual uptime.
  42. static uint32_t rtc_time_cali=0;
  43. static uint32_t last_rtc_time=0;
  44. static uint64_t last_rtc_time_us=0;
  45. static sint32_t soft_watchdog = -1;
  46. static os_timer_t rtc_timer;
  47. static void alarm_timer_common(void* arg){
  48. tmr_t *tmr = (tmr_t *) arg;
  49. if(tmr->lua_ref > 0) {
  50. lua_State* L = lua_getstate();
  51. lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  52. lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
  53. if (tmr->mode != TIMER_MODE_AUTO) {
  54. if(tmr->mode == TIMER_MODE_SINGLE) {
  55. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  56. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
  57. tmr->mode = TIMER_MODE_OFF;
  58. } else if (tmr->mode == TIMER_MODE_SEMI) {
  59. tmr->mode |= TIMER_IDLE_FLAG;
  60. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
  61. }
  62. }
  63. luaL_pcallx(L, 1, 0);
  64. }
  65. }
  66. // Lua: tmr.delay( us )
  67. static int tmr_delay( lua_State* L ){
  68. sint32_t us = luaL_checkinteger(L, 1);
  69. luaL_argcheck(L, us>0, 1, "wrong arg range");
  70. while(us > 0){
  71. os_delay_us(us >= 1000000 ? 1000000 : us);
  72. system_soft_wdt_feed ();
  73. us -= 1000000;
  74. }
  75. return 0;
  76. }
  77. // Lua: tmr.now() , return system timer in us
  78. static int tmr_now(lua_State* L){
  79. lua_pushinteger(L, (uint32_t) (0x7FFFFFFF & system_get_time()));
  80. return 1;
  81. }
  82. // Lua: tmr.ccount() , returns CCOUNT register
  83. static int tmr_ccount(lua_State* L){
  84. lua_pushinteger(L, CCOUNT_REG);
  85. return 1;
  86. }
  87. /*
  88. ** Health warning: this is also called DIRECTLY from alarm() which assumes that the Lua
  89. ** stack is preserved for the following start(), so the stack MUST be balanced here.
  90. */
  91. // Lua: t:register( interval, mode, function )
  92. static int tmr_register(lua_State* L) {
  93. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  94. uint32_t interval = luaL_checkinteger(L, 2);
  95. uint8_t mode = luaL_checkinteger(L, 3);
  96. luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
  97. luaL_argcheck(L, (mode == TIMER_MODE_SINGLE || mode == TIMER_MODE_SEMI || mode == TIMER_MODE_AUTO), 3, "Invalid mode");
  98. luaL_argcheck(L, lua_isfunction(L, 4), 4, "Must be function");
  99. //get the lua function reference
  100. lua_pushvalue(L, 4);
  101. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  102. os_timer_disarm(&tmr->os);
  103. luaL_reref(L, LUA_REGISTRYINDEX, &tmr->lua_ref);
  104. tmr->mode = mode|TIMER_IDLE_FLAG;
  105. tmr->interval = interval;
  106. os_timer_setfn(&tmr->os, alarm_timer_common, tmr);
  107. return 0;
  108. }
  109. // Lua: t:start( [restart] )
  110. static int tmr_start(lua_State* L){
  111. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  112. lua_settop(L, 2);
  113. luaL_argcheck(L, lua_isboolean(L, 2) || lua_isnil(L, 2), 2, "boolean expected");
  114. int restart = lua_toboolean(L, 2);
  115. lua_settop(L, 1); /* we need to have userdata on top of the stack */
  116. if (tmr->self_ref == LUA_NOREF)
  117. tmr->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  118. //we return false if the timer is not idle and is not to be restarted
  119. int idle = tmr->mode&TIMER_IDLE_FLAG;
  120. if(!(idle || restart)){
  121. lua_pushboolean(L, false);
  122. }else{
  123. if (!idle) {os_timer_disarm(&tmr->os);}
  124. tmr->mode &= ~TIMER_IDLE_FLAG;
  125. os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
  126. lua_pushboolean(L, true);
  127. }
  128. return 1;
  129. }
  130. // Lua: t:alarm( interval, repeat, function )
  131. static int tmr_alarm(lua_State* L){
  132. tmr_register(L);
  133. /* remove tmr.alarm's other then the 1st UD parameters from Lua stack.
  134. tmr.start expects UD and optional restart parameter. */
  135. lua_settop(L, 1);
  136. return tmr_start(L);
  137. }
  138. // Lua: t:stop()
  139. static int tmr_stop(lua_State* L){
  140. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  141. int idle = tmr->mode == TIMER_MODE_OFF || (tmr->mode & TIMER_IDLE_FLAG);
  142. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
  143. if(!idle)
  144. os_timer_disarm(&tmr->os);
  145. tmr->mode |= TIMER_IDLE_FLAG;
  146. lua_pushboolean(L, !idle); /* return false if the timer is idle (or not registered) */
  147. return 1;
  148. }
  149. #ifdef TIMER_SUSPEND_ENABLE
  150. #define TMR_SUSPEND_REMOVED_MSG "This feature has been removed, we apologize for any inconvenience this may have caused."
  151. #define tmr_suspend tmr_suspend_removed
  152. #define tmr_resume tmr_suspend_removed
  153. #define tmr_suspend_all tmr_suspend_removed
  154. #define tmr_resume_all tmr_suspend_removed
  155. static int tmr_suspend_removed(lua_State* L){
  156. return luaL_error(L, TMR_SUSPEND_REMOVED_MSG);
  157. }
  158. #endif
  159. // Lua: t:unregister()
  160. static int tmr_unregister(lua_State* L){
  161. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  162. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->self_ref);
  163. luaL_unref2(L, LUA_REGISTRYINDEX, tmr->lua_ref);
  164. if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
  165. os_timer_disarm(&tmr->os);
  166. tmr->mode = TIMER_MODE_OFF;
  167. return 0;
  168. }
  169. // Lua: t:interval( interval )
  170. static int tmr_interval(lua_State* L){
  171. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  172. uint32_t interval = luaL_checkinteger(L, 2);
  173. luaL_argcheck(L, (interval > 0 && interval <= MAX_TIMEOUT), 2, MAX_TIMEOUT_ERR_STR);
  174. if(tmr->mode != TIMER_MODE_OFF){
  175. tmr->interval = interval;
  176. if(!(tmr->mode&TIMER_IDLE_FLAG)){
  177. os_timer_disarm(&tmr->os);
  178. os_timer_arm(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO);
  179. }
  180. }
  181. return 0;
  182. }
  183. // Lua: t:state()
  184. static int tmr_state(lua_State* L){
  185. tmr_t *tmr = (tmr_t *) luaL_checkudata(L, 1, "tmr.timer");
  186. if(tmr->mode == TIMER_MODE_OFF){
  187. lua_pushnil(L);
  188. return 1;
  189. }
  190. lua_pushboolean(L, (tmr->mode & TIMER_IDLE_FLAG) == 0);
  191. lua_pushinteger(L, tmr->mode & (~TIMER_IDLE_FLAG));
  192. return 2;
  193. }
  194. // Lua: tmr.wdclr()
  195. static int tmr_wdclr( lua_State* L ){
  196. system_soft_wdt_feed ();
  197. return 0;
  198. }
  199. // The on ESP8266 system_rtc_clock_cali_proc() returns a fixed point value
  200. // (12 bit fraction part), giving how many rtc clock ticks represent 1us.
  201. // The high 64 bits of the uint64_t multiplication are not needed)
  202. static uint32_t rtc2usec(uint64_t rtc){
  203. return (rtc*rtc_time_cali)>>12;
  204. }
  205. // This returns the number of microseconds uptime. Note that it relies on
  206. // the rtc clock, which is notoriously temperature dependent
  207. inline static uint64_t rtc_timer_update(bool do_calibration){
  208. if (do_calibration || rtc_time_cali==0)
  209. rtc_time_cali=system_rtc_clock_cali_proc();
  210. uint32_t current = system_get_rtc_time();
  211. uint32_t since_last=current-last_rtc_time; // This will transparently deal with wraparound
  212. uint32_t us_since_last=rtc2usec(since_last);
  213. uint64_t now=last_rtc_time_us+us_since_last;
  214. // Only update if at least 100ms has passed since we last updated.
  215. // This prevents the rounding errors in rtc2usec from accumulating
  216. if (us_since_last>=100000){
  217. last_rtc_time=current;
  218. last_rtc_time_us=now;
  219. }
  220. return now;
  221. }
  222. void rtc_callback(void *arg){
  223. rtc_timer_update(true);
  224. if(soft_watchdog >= 0){
  225. soft_watchdog--;
  226. if(soft_watchdog < 0)
  227. system_restart();
  228. }
  229. }
  230. // Lua: tmr.time() , return rtc time in second
  231. static int tmr_time( lua_State* L ){
  232. uint64_t us=rtc_timer_update(false);
  233. lua_pushinteger(L, us/1000000);
  234. return 1;
  235. }
  236. // Lua: tmr.softwd( value )
  237. static int tmr_softwd( lua_State* L ){
  238. soft_watchdog = luaL_checkinteger(L, 1);
  239. // NO check is required as negative Values mean that the timer is disabled.
  240. return 0;
  241. }
  242. // Lua: tmr.create()
  243. static int tmr_create( lua_State *L ) {
  244. tmr_t *ud = (tmr_t *)lua_newuserdata(L, sizeof(*ud));
  245. luaL_getmetatable(L, "tmr.timer");
  246. lua_setmetatable(L, -2);
  247. *ud = (tmr_t) {{0}, LUA_NOREF, LUA_NOREF, 0, TIMER_MODE_OFF};
  248. return 1;
  249. }
  250. // Module function map
  251. LROT_BEGIN(tmr_dyn, NULL, LROT_MASK_GC_INDEX)
  252. LROT_FUNCENTRY( __gc, tmr_unregister )
  253. LROT_TABENTRY( __index, tmr_dyn )
  254. LROT_FUNCENTRY( register, tmr_register )
  255. LROT_FUNCENTRY( alarm, tmr_alarm )
  256. LROT_FUNCENTRY( start, tmr_start )
  257. LROT_FUNCENTRY( stop, tmr_stop )
  258. LROT_FUNCENTRY( unregister, tmr_unregister )
  259. LROT_FUNCENTRY( state, tmr_state )
  260. LROT_FUNCENTRY( interval, tmr_interval )
  261. #ifdef TIMER_SUSPEND_ENABLE
  262. LROT_FUNCENTRY( suspend, tmr_suspend )
  263. LROT_FUNCENTRY( resume, tmr_resume )
  264. #endif
  265. LROT_END(tmr_dyn, NULL, LROT_MASK_GC_INDEX)
  266. LROT_BEGIN(tmr, NULL, 0)
  267. LROT_FUNCENTRY( delay, tmr_delay )
  268. LROT_FUNCENTRY( now, tmr_now )
  269. LROT_FUNCENTRY( wdclr, tmr_wdclr )
  270. LROT_FUNCENTRY( softwd, tmr_softwd )
  271. LROT_FUNCENTRY( time, tmr_time )
  272. LROT_FUNCENTRY( ccount, tmr_ccount )
  273. #ifdef TIMER_SUSPEND_ENABLE
  274. LROT_FUNCENTRY( suspend_all, tmr_suspend_all )
  275. LROT_FUNCENTRY( resume_all, tmr_resume_all )
  276. #endif
  277. LROT_FUNCENTRY( create, tmr_create )
  278. LROT_NUMENTRY( ALARM_SINGLE, TIMER_MODE_SINGLE )
  279. LROT_NUMENTRY( ALARM_SEMI, TIMER_MODE_SEMI )
  280. LROT_NUMENTRY( ALARM_AUTO, TIMER_MODE_AUTO )
  281. LROT_END(tmr, NULL, 0)
  282. #include "pm/swtimer.h"
  283. int luaopen_tmr( lua_State *L ){
  284. luaL_rometatable(L, "tmr.timer", LROT_TABLEREF(tmr_dyn));
  285. last_rtc_time=system_get_rtc_time(); // Right now is time 0
  286. last_rtc_time_us=0;
  287. os_timer_disarm(&rtc_timer);
  288. os_timer_setfn(&rtc_timer, rtc_callback, NULL);
  289. os_timer_arm(&rtc_timer, 1000, 1);
  290. // The function rtc_callback calls the a function that calibrates the SoftRTC
  291. // for drift in the esp8266's clock. My guess: after the duration of light_sleep
  292. // there is bound to be some drift in the clock, so a calibration is due.
  293. SWTIMER_REG_CB(rtc_callback, SWTIMER_RESUME);
  294. // The function alarm_timer_common handles timers created by the developer via
  295. // tmr.create(). No reason not to resume the timers, so resume em'.
  296. SWTIMER_REG_CB(alarm_timer_common, SWTIMER_RESUME);
  297. return 0;
  298. }
  299. NODEMCU_MODULE(TMR, "tmr", tmr, luaopen_tmr);