gpio_pulse.c 12 KB

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