gpio_pulse.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include "lmem.h"
  4. #include "platform.h"
  5. #include "user_interface.h"
  6. #include <stdint.h>
  7. #include <string.h>
  8. #include "gpio.h"
  9. #include "hw_timer.h"
  10. #include "pin_map.h"
  11. #include "driver/gpio16.h"
  12. #define TIMER_OWNER (('P' << 8) + 'U')
  13. #define xstr(s) str(s)
  14. #define str(s) #s
  15. // Maximum delay in microseconds
  16. #define DELAY_LIMIT 64000000
  17. typedef struct {
  18. uint32_t gpio_set;
  19. uint32_t gpio_clr;
  20. int32_t delay;
  21. int32_t delay_min;
  22. int32_t delay_max;
  23. uint32_t count;
  24. uint32_t count_left;
  25. uint16_t loop;
  26. } pulse_entry_t;
  27. typedef struct {
  28. uint32_t entry_count;
  29. volatile uint32_t steps;
  30. volatile uint16_t entry_pos;
  31. volatile uint16_t active_pos;
  32. volatile int16_t stop_pos; // -1 is stop nowhere, -2 is stop everywhere, otherwise is stop point
  33. pulse_entry_t *entry;
  34. volatile uint32_t expected_end_time;
  35. volatile uint32_t desired_end_time;
  36. volatile int32_t next_adjust;
  37. volatile int32_t pending_delay;
  38. volatile int cb_ref;
  39. } pulse_t;
  40. static int active_pulser_ref;
  41. static pulse_t *active_pulser;
  42. static platform_task_handle_t tasknumber;
  43. static int gpio_pulse_push_state(lua_State *L, pulse_t *pulser) {
  44. uint32_t now;
  45. uint32_t expected_end_time;
  46. uint32_t active_pos;
  47. uint32_t steps;
  48. do {
  49. now = 0x7FFFFFFF & system_get_time();
  50. expected_end_time = pulser->expected_end_time;
  51. active_pos = pulser->active_pos;
  52. steps = pulser->steps;
  53. } while (expected_end_time != pulser->expected_end_time ||
  54. active_pos != pulser->active_pos ||
  55. steps != pulser->steps);
  56. if (active_pos >= pulser->entry_count) {
  57. lua_pushnil(L);
  58. } else {
  59. lua_pushinteger(L, active_pos + 1); // Lua is 1 offset
  60. }
  61. lua_pushinteger(L, steps);
  62. int32_t diff = (expected_end_time - now) & 0x7fffffff;
  63. lua_pushinteger(L, (diff << 1) >> 1);
  64. lua_pushinteger(L, now);
  65. return 4;
  66. }
  67. static int gpio_pulse_getstate(lua_State *L) {
  68. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  69. return gpio_pulse_push_state(L, pulser);
  70. }
  71. static int gpio_pulse_stop(lua_State *L) {
  72. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  73. if (pulser != active_pulser) {
  74. return 0;
  75. }
  76. int argno = 2;
  77. int32_t stop_pos = -2;
  78. if (lua_type(L, argno) == LUA_TNUMBER) {
  79. stop_pos = luaL_checkinteger(L, 2);
  80. if (stop_pos != -2) {
  81. if (stop_pos < 1 || stop_pos > pulser->entry_count) {
  82. return luaL_error( L, "bad stop position: %d (valid range 1 - %d)", stop_pos, pulser->entry_count );
  83. }
  84. stop_pos = stop_pos - 1;
  85. }
  86. argno++;
  87. }
  88. if (lua_isfunction(L, argno)) {
  89. lua_pushvalue(L, argno);
  90. } else {
  91. return luaL_error( L, "missing callback" );
  92. }
  93. int new_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  94. int cb_ref = pulser->cb_ref;
  95. pulser->cb_ref = LUA_NOREF;
  96. pulser->stop_pos = -1;
  97. pulser->cb_ref = new_cb_ref;
  98. pulser->stop_pos = stop_pos;
  99. luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
  100. lua_pushboolean(L, 1);
  101. return 1;
  102. }
  103. static int gpio_pulse_delete(lua_State *L) {
  104. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  105. if (pulser == active_pulser) {
  106. return 0;
  107. }
  108. luaL_unref(L, LUA_REGISTRYINDEX, pulser->cb_ref);
  109. return 0;
  110. }
  111. static void fill_entry_from_table(lua_State *L, pulse_entry_t *entry) {
  112. if (lua_type(L, -1) != LUA_TTABLE) {
  113. luaL_error(L, "All entries must be tables");
  114. }
  115. lua_pushnil(L); // key position
  116. while (lua_next(L, -2)) {
  117. // stack now contains: -1 => value; -2 => key; -3 => table
  118. if (lua_type(L, -2) == LUA_TNUMBER) {
  119. int pin = luaL_checkint(L, -2);
  120. int value = luaL_checkint(L, -1);
  121. if (pin < 0 || pin >= GPIO_PIN_NUM) {
  122. luaL_error(L, "pin number %d must be in range 0 .. %d", pin, GPIO_PIN_NUM - 1);
  123. }
  124. if (value) {
  125. entry->gpio_set |= BIT(pin_num[pin]);
  126. } else {
  127. entry->gpio_clr |= BIT(pin_num[pin]);
  128. }
  129. } else {
  130. const char *str = luaL_checkstring(L, -2);
  131. if (strcmp(str, "delay") == 0) {
  132. entry->delay = luaL_checkint(L, -1);
  133. if (entry->delay < 0 || entry->delay > DELAY_LIMIT) {
  134. luaL_error(L, "delay of %d must be in the range 0 .. " xstr(DELAY_LIMIT) " microseconds", entry->delay);
  135. }
  136. } else if (strcmp(str, "min") == 0) {
  137. entry->delay_min = luaL_checkint(L, -1);
  138. if (entry->delay_min < 0 || entry->delay_min > DELAY_LIMIT) {
  139. luaL_error(L, "delay minimum of %d must be in the range 0 .. " xstr(DELAY_LIMIT) " microseconds", entry->delay_min);
  140. }
  141. } else if (strcmp(str, "max") == 0) {
  142. entry->delay_max = luaL_checkint(L, -1);
  143. if (entry->delay_max < 0 || entry->delay_max > DELAY_LIMIT) {
  144. luaL_error(L, "delay maximum of %d must be in the range 0 .. " xstr(DELAY_LIMIT) " microseconds", entry->delay_max);
  145. }
  146. } else if (strcmp(str, "count") == 0) {
  147. entry->count = luaL_checkint(L, -1);
  148. } else if (strcmp(str, "loop") == 0) {
  149. entry->loop = luaL_checkint(L, -1);
  150. } else {
  151. luaL_error(L, "Unrecognized key found: %s", str);
  152. }
  153. }
  154. lua_pop(L, 1);
  155. }
  156. if (entry->delay_min != -1 || entry->delay_max != -1) {
  157. if (entry->delay_min == -1) {
  158. entry->delay_min = 0;
  159. }
  160. if (entry->delay_min > entry->delay ||
  161. entry->delay_max < entry->delay) {
  162. luaL_error(L, "Delay of %d must be between min and max", entry->delay);
  163. }
  164. }
  165. lua_pop(L, 1);
  166. }
  167. static int gpio_pulse_build(lua_State *L) {
  168. // Take a table argument
  169. luaL_checktype(L, 1, LUA_TTABLE);
  170. // First figure out how big we need the block to be
  171. size_t size = lua_objlen(L, 1);
  172. if (size > 100) {
  173. return luaL_error(L, "table is too large: %d entries is more than 100", size);
  174. }
  175. size_t memsize = sizeof(pulse_t) + size * sizeof(pulse_entry_t);
  176. pulse_t *pulser = (pulse_t *) lua_newuserdata(L, memsize);
  177. memset(pulser, 0, memsize);
  178. //
  179. // Associate its metatable
  180. luaL_getmetatable(L, "gpio.pulse");
  181. lua_setmetatable(L, -2);
  182. pulser->entry = (pulse_entry_t *) (pulser + 1);
  183. pulser->entry_count = size;
  184. size_t i;
  185. for (i = 0; i < size; i++) {
  186. pulse_entry_t *entry = pulser->entry + i;
  187. entry->delay_min = -1;
  188. entry->delay_max = -1;
  189. lua_rawgeti(L, 1, i + 1);
  190. fill_entry_from_table(L, entry);
  191. }
  192. return 1;
  193. }
  194. static int gpio_pulse_update(lua_State *L) {
  195. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  196. int entry_pos = luaL_checkinteger(L, 2);
  197. if (entry_pos < 1 || entry_pos > pulser->entry_count) {
  198. return luaL_error(L, "entry number must be in range 1 .. %d", pulser->entry_count);
  199. }
  200. pulse_entry_t *entry = pulser->entry + entry_pos - 1;
  201. pulse_entry_t new_entry = *entry;
  202. lua_pushvalue(L, 3);
  203. fill_entry_from_table(L, &new_entry);
  204. // Now do the update
  205. ETS_FRC1_INTR_DISABLE();
  206. *entry = new_entry;
  207. ETS_FRC1_INTR_ENABLE();
  208. return 0;
  209. }
  210. static int gpio_pulse_adjust(lua_State *L) {
  211. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  212. if (active_pulser != pulser) {
  213. return 0;
  214. }
  215. int offset = luaL_checkinteger(L, 2);
  216. // This will alter the next adjustable
  217. pulser->next_adjust = offset;
  218. int rc = gpio_pulse_push_state(L, active_pulser);
  219. return rc;
  220. }
  221. static int gpio_pulse_cancel(lua_State *L) {
  222. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  223. if (active_pulser != pulser) {
  224. return 0;
  225. }
  226. // Shut off the timer
  227. platform_hw_timer_close(TIMER_OWNER);
  228. int rc = gpio_pulse_push_state(L, active_pulser);
  229. active_pulser = NULL;
  230. int pulser_ref = active_pulser_ref;
  231. active_pulser_ref = LUA_NOREF;
  232. luaL_unref(L, LUA_REGISTRYINDEX, pulser_ref);
  233. return rc;
  234. }
  235. static void ICACHE_RAM_ATTR gpio_pulse_timeout(os_param_t p) {
  236. (void) p;
  237. uint32_t now = system_get_time();
  238. int delay;
  239. if (active_pulser) {
  240. delay = active_pulser->pending_delay;
  241. if (delay > 0) {
  242. if (delay > 1200000) {
  243. delay = 1000000;
  244. }
  245. active_pulser->pending_delay -= delay;
  246. platform_hw_timer_arm_us(TIMER_OWNER, delay);
  247. return;
  248. }
  249. }
  250. do {
  251. active_pulser->active_pos = active_pulser->entry_pos;
  252. if (!active_pulser || active_pulser->entry_pos >= active_pulser->entry_count) {
  253. if (active_pulser) {
  254. active_pulser->steps++;
  255. }
  256. platform_hw_timer_close(TIMER_OWNER);
  257. platform_post_low(tasknumber, 0);
  258. return;
  259. }
  260. active_pulser->steps++;
  261. pulse_entry_t *entry = active_pulser->entry + active_pulser->entry_pos;
  262. // Yes, this means that there is more skew on D0 than on other pins....
  263. if (entry->gpio_set & 0x10000) {
  264. gpio16_output_set(1);
  265. }
  266. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, entry->gpio_set);
  267. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, entry->gpio_clr);
  268. if (entry->gpio_clr & 0x10000) {
  269. gpio16_output_set(0);
  270. }
  271. int16_t stop = active_pulser->stop_pos;
  272. if (stop == -2 || stop == active_pulser->entry_pos) {
  273. platform_hw_timer_close(TIMER_OWNER);
  274. platform_post_low(tasknumber, 0);
  275. return;
  276. }
  277. if (entry->loop) {
  278. if (entry->count_left == 0) {
  279. entry->count_left = entry->count + 1;
  280. }
  281. if (--entry->count_left >= 1) {
  282. active_pulser->entry_pos = entry->loop - 1; // zero offset
  283. } else {
  284. active_pulser->entry_pos++;
  285. }
  286. } else {
  287. active_pulser->entry_pos++;
  288. }
  289. delay = entry->delay;
  290. int delay_offset = 0;
  291. if (entry->delay_min != -1) {
  292. int offset = active_pulser->next_adjust;
  293. active_pulser->next_adjust = 0;
  294. delay_offset = ((0x7fffffff & (now - active_pulser->desired_end_time)) << 1) >> 1;
  295. delay -= delay_offset;
  296. delay += offset;
  297. //dbg_printf("%d(et %d diff %d): Delay was %d us, offset = %d, delay_offset = %d, new delay = %d, range=%d..%d\n",
  298. // now, active_pulser->desired_end_time, now - active_pulser->desired_end_time,
  299. // entry->delay, offset, delay_offset, delay, entry->delay_min, entry->delay_max);
  300. if (delay < entry->delay_min) {
  301. // we can't delay as little as 'delay', so we need to adjust
  302. // the next period as well.
  303. active_pulser->next_adjust = (entry->delay - entry->delay_min) + offset;
  304. delay = entry->delay_min;
  305. } else if (delay > entry->delay_max) {
  306. // we can't delay as much as 'delay', so we need to adjust
  307. // the next period as well.
  308. active_pulser->next_adjust = (entry->delay - entry->delay_max) + offset;
  309. delay = entry->delay_max;
  310. }
  311. }
  312. active_pulser->desired_end_time += delay + delay_offset;
  313. active_pulser->expected_end_time = system_get_time() + delay;
  314. } while (delay < 3);
  315. if (delay > 1200000) {
  316. active_pulser->pending_delay = delay - 1000000;
  317. delay = 1000000;
  318. }
  319. platform_hw_timer_arm_us(TIMER_OWNER, delay);
  320. }
  321. static int gpio_pulse_start(lua_State *L) {
  322. pulse_t *pulser = luaL_checkudata(L, 1, "gpio.pulse");
  323. if (active_pulser) {
  324. return luaL_error(L, "pulse operation already in progress");
  325. }
  326. int argno = 2;
  327. int initial_adjust;
  328. if (lua_type(L, argno) == LUA_TNUMBER) {
  329. initial_adjust = luaL_checkinteger(L, argno);
  330. argno++;
  331. }
  332. if (lua_isfunction(L, argno)) {
  333. lua_pushvalue(L, argno);
  334. } else {
  335. return luaL_error( L, "missing callback" );
  336. }
  337. luaL_unref(L, LUA_REGISTRYINDEX, pulser->cb_ref);
  338. pulser->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  339. active_pulser = pulser;
  340. lua_pushvalue(L, 1);
  341. active_pulser_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  342. size_t i;
  343. for (i = 0; i < pulser->entry_count; i++) {
  344. pulser->entry[i].count_left = 0;
  345. }
  346. pulser->entry_pos = 0;
  347. pulser->active_pos = 0;
  348. pulser->steps = 0;
  349. pulser->stop_pos = -1;
  350. pulser->next_adjust = initial_adjust;
  351. // Now start things up
  352. if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, FALSE)) {
  353. // Failed to init the timer
  354. luaL_error(L, "Unable to initialize timer");
  355. }
  356. active_pulser->expected_end_time = 0x7fffffff & system_get_time();
  357. platform_hw_timer_set_func(TIMER_OWNER, gpio_pulse_timeout, 0);
  358. gpio_pulse_timeout(0);
  359. return 0;
  360. }
  361. static void gpio_pulse_task(os_param_t param, uint8_t prio)
  362. {
  363. (void) param;
  364. (void) prio;
  365. if (active_pulser) {
  366. lua_State *L = lua_getstate();
  367. // Invoke the callback
  368. lua_rawgeti(L, LUA_REGISTRYINDEX, active_pulser->cb_ref);
  369. int rc = gpio_pulse_push_state(L, active_pulser);
  370. active_pulser = NULL;
  371. int pulser_ref = active_pulser_ref;
  372. active_pulser_ref = LUA_NOREF;
  373. luaL_unref(L, LUA_REGISTRYINDEX, pulser_ref);
  374. luaL_pcallx(L, rc, 0);
  375. }
  376. }
  377. LROT_BEGIN(pulse, NULL, LROT_MASK_GC_INDEX)
  378. LROT_FUNCENTRY( __gc, gpio_pulse_delete )
  379. LROT_TABENTRY( __index, pulse )
  380. LROT_FUNCENTRY( getstate, gpio_pulse_getstate )
  381. LROT_FUNCENTRY( stop, gpio_pulse_stop )
  382. LROT_FUNCENTRY( cancel, gpio_pulse_cancel )
  383. LROT_FUNCENTRY( start, gpio_pulse_start )
  384. LROT_FUNCENTRY( adjust, gpio_pulse_adjust )
  385. LROT_FUNCENTRY( update, gpio_pulse_update )
  386. LROT_END(pulse, NULL, LROT_MASK_GC_INDEX)
  387. LROT_BEGIN(gpio_pulse, NULL, 0)
  388. LROT_FUNCENTRY( build, gpio_pulse_build )
  389. LROT_END(gpio_pulse, NULL, 0)
  390. int gpio_pulse_init(lua_State *L)
  391. {
  392. luaL_rometatable(L, "gpio.pulse", LROT_TABLEREF(pulse));
  393. tasknumber = platform_task_get_id(gpio_pulse_task);
  394. return 0;
  395. }
  396. NODEMCU_MODULE(GPIOPULSE, "gpiopulse", gpio_pulse, gpio_pulse_init);