gpio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Module for interfacing with GPIO
  2. //#define NODE_DEBUG
  3. #include "module.h"
  4. #include "lauxlib.h"
  5. #include "lmem.h"
  6. #include "platform.h"
  7. #include "user_interface.h"
  8. #include "c_types.h"
  9. #include "c_string.h"
  10. #include "gpio.h"
  11. #include "hw_timer.h"
  12. #define PULLUP PLATFORM_GPIO_PULLUP
  13. #define FLOAT PLATFORM_GPIO_FLOAT
  14. #define OUTPUT PLATFORM_GPIO_OUTPUT
  15. #define OPENDRAIN PLATFORM_GPIO_OPENDRAIN
  16. #define INPUT PLATFORM_GPIO_INPUT
  17. #define INTERRUPT PLATFORM_GPIO_INT
  18. #define HIGH PLATFORM_GPIO_HIGH
  19. #define LOW PLATFORM_GPIO_LOW
  20. #ifdef GPIO_INTERRUPT_ENABLE
  21. // We also know that the non-level interrupt types are < LOLEVEL, and that
  22. // HILEVEL is > LOLEVEL. Since this is burned into the hardware it is not
  23. // going to change.
  24. #define INTERRUPT_TYPE_IS_LEVEL(x) ((x) >= GPIO_PIN_INTR_LOLEVEL)
  25. static int gpio_cb_ref[GPIO_PIN_NUM];
  26. // This task is scheduled by the ISR and is used
  27. // to initiate the Lua-land gpio.trig() callback function
  28. // It also re-enables the pin interrupt, so that we get another callback queued
  29. static void gpio_intr_callback_task (task_param_t param, uint8 priority)
  30. {
  31. unsigned pin = param >> 1;
  32. unsigned level = param & 1;
  33. UNUSED(priority);
  34. NODE_DBG("pin:%d, level:%d \n", pin, level);
  35. if(gpio_cb_ref[pin] != LUA_NOREF) {
  36. // GPIO callbacks are run in L0 and inlcude the level as a parameter
  37. lua_State *L = lua_getstate();
  38. NODE_DBG("Calling: %08x\n", gpio_cb_ref[pin]);
  39. //
  40. if (!INTERRUPT_TYPE_IS_LEVEL(pin_int_type[pin])) {
  41. // Edge triggered -- re-enable the interrupt
  42. platform_gpio_intr_init(pin, pin_int_type[pin]);
  43. }
  44. // Do the actual callback
  45. lua_rawgeti(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
  46. lua_pushinteger(L, level);
  47. lua_call(L, 1, 0);
  48. if (INTERRUPT_TYPE_IS_LEVEL(pin_int_type[pin])) {
  49. // Level triggered -- re-enable the callback
  50. platform_gpio_intr_init(pin, pin_int_type[pin]);
  51. }
  52. }
  53. }
  54. // Lua: trig( pin, type, function )
  55. static int lgpio_trig( lua_State* L )
  56. {
  57. unsigned pin = luaL_checkinteger( L, 1 );
  58. static const char * const opts[] = {"none", "up", "down", "both", "low", "high", NULL};
  59. static const int opts_type[] = {
  60. GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_POSEDGE, GPIO_PIN_INTR_NEGEDGE,
  61. GPIO_PIN_INTR_ANYEDGE, GPIO_PIN_INTR_LOLEVEL, GPIO_PIN_INTR_HILEVEL
  62. };
  63. luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin");
  64. int old_pin_ref = gpio_cb_ref[pin];
  65. int type = opts_type[luaL_checkoption(L, 2, "none", opts)];
  66. if (type == GPIO_PIN_INTR_DISABLE) {
  67. // "none" clears the callback
  68. gpio_cb_ref[pin] = LUA_NOREF;
  69. } else if (lua_gettop(L)==2 && old_pin_ref != LUA_NOREF) {
  70. // keep the old one if no callback
  71. old_pin_ref = LUA_NOREF;
  72. } else if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) {
  73. // set up the new callback if present
  74. lua_pushvalue(L, 3);
  75. gpio_cb_ref[pin] = luaL_ref(L, LUA_REGISTRYINDEX);
  76. } else {
  77. // invalid combination, so clear down any old callback and throw an error
  78. if(old_pin_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, old_pin_ref);
  79. luaL_argcheck(L, 0, 3, "invalid callback type");
  80. }
  81. // unreference any overwritten callback
  82. if(old_pin_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, old_pin_ref);
  83. NODE_DBG("Pin data: %d %d %08x, %d %d %d, %08x\n",
  84. pin, type, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], gpio_cb_ref[pin]);
  85. platform_gpio_intr_init(pin, type);
  86. return 0;
  87. }
  88. #endif
  89. // Lua: mode( pin, mode, pullup )
  90. static int lgpio_mode( lua_State* L )
  91. {
  92. unsigned pin = luaL_checkinteger( L, 1 );
  93. unsigned mode = luaL_checkinteger( L, 2 );
  94. unsigned pullup = luaL_optinteger( L, 3, FLOAT );
  95. luaL_argcheck(L, platform_gpio_exists(pin) && (mode!=INTERRUPT || pin>0), 1, "Invalid pin");
  96. luaL_argcheck(L, mode==OUTPUT || mode==OPENDRAIN || mode==INPUT
  97. #ifdef GPIO_INTERRUPT_ENABLE
  98. || mode==INTERRUPT
  99. #endif
  100. , 2, "wrong arg type" );
  101. if(pullup!=FLOAT) pullup = PULLUP;
  102. NODE_DBG("pin,mode,pullup= %d %d %d\n",pin,mode,pullup);
  103. NODE_DBG("Pin data at mode: %d %08x, %d %d %d, %08x\n",
  104. pin, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], gpio_cb_ref[pin]);
  105. #ifdef GPIO_INTERRUPT_ENABLE
  106. if (mode != INTERRUPT){ // disable interrupt
  107. if(gpio_cb_ref[pin] != LUA_NOREF){
  108. luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
  109. gpio_cb_ref[pin] = LUA_NOREF;
  110. }
  111. }
  112. #endif
  113. if( platform_gpio_mode( pin, mode, pullup ) < 0 )
  114. return luaL_error( L, "wrong pin num." );
  115. return 0;
  116. }
  117. // Lua: read( pin )
  118. static int lgpio_read( lua_State* L )
  119. {
  120. unsigned pin = luaL_checkinteger( L, 1 );
  121. MOD_CHECK_ID( gpio, pin );
  122. lua_pushinteger( L, platform_gpio_read( pin ) );
  123. return 1;
  124. }
  125. // Lua: write( pin, level )
  126. static int lgpio_write( lua_State* L )
  127. {
  128. unsigned pin = luaL_checkinteger( L, 1 );
  129. unsigned level = luaL_checkinteger( L, 2 );
  130. MOD_CHECK_ID( gpio, pin );
  131. luaL_argcheck(L, level==HIGH || level==LOW, 2, "wrong level type" );
  132. platform_gpio_write(pin, level);
  133. return 0;
  134. }
  135. #define DELAY_TABLE_MAX_LEN 256
  136. #define delayMicroseconds os_delay_us
  137. // Lua: serout( pin, firstLevel, delay_table[, repeat_num[, callback]])
  138. // gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
  139. // gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
  140. // gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
  141. // gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
  142. // gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
  143. // gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
  144. // gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
  145. // gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
  146. typedef struct
  147. {
  148. unsigned pin;
  149. unsigned level;
  150. uint32 index;
  151. uint32 repeats;
  152. uint32 *delay_table;
  153. uint32 tablelen;
  154. task_handle_t done_taskid;
  155. int lua_done_ref; // callback when transmission is done
  156. } serout_t;
  157. static serout_t serout;
  158. static const os_param_t TIMER_OWNER = 0x6770696f; // "gpio"
  159. static void seroutasync_done (task_param_t arg)
  160. {
  161. lua_State *L = lua_getstate();
  162. luaM_freearray(L, serout.delay_table, serout.tablelen, uint32);
  163. serout.delay_table = NULL;
  164. if (serout.lua_done_ref != LUA_NOREF) {
  165. lua_rawgeti (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
  166. luaL_unref (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
  167. serout.lua_done_ref = LUA_NOREF;
  168. if (lua_pcall(L, 0, 0, 0)) {
  169. // Uncaught Error. Print instead of sudden reset
  170. luaL_error(L, "error: %s", lua_tostring(L, -1));
  171. }
  172. }
  173. }
  174. static void ICACHE_RAM_ATTR seroutasync_cb(os_param_t p) {
  175. (void) p;
  176. if (serout.index < serout.tablelen) {
  177. GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[serout.pin]), serout.level);
  178. serout.level = serout.level==LOW ? HIGH : LOW;
  179. platform_hw_timer_arm_us(TIMER_OWNER, serout.delay_table[serout.index]);
  180. serout.index++;
  181. if (serout.repeats && serout.index>=serout.tablelen) {serout.index=0; serout.repeats--;}
  182. } else {
  183. platform_hw_timer_close(TIMER_OWNER);
  184. task_post_low (serout.done_taskid, (task_param_t)0);
  185. }
  186. }
  187. static int lgpio_serout( lua_State* L )
  188. {
  189. serout.pin = luaL_checkinteger( L, 1 );
  190. serout.level = luaL_checkinteger( L, 2 );
  191. serout.repeats = luaL_optint( L, 4, 1 )-1;
  192. luaL_unref (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
  193. uint8_t is_async = FALSE;
  194. if (!lua_isnoneornil(L, 5)) {
  195. if (lua_isnumber(L, 5)) {
  196. serout.lua_done_ref = LUA_NOREF;
  197. } else {
  198. lua_pushvalue(L, 5);
  199. serout.lua_done_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  200. }
  201. is_async = TRUE;
  202. } else {
  203. serout.lua_done_ref = LUA_NOREF;
  204. }
  205. if (serout.delay_table) {
  206. luaM_freearray(L, serout.delay_table, serout.tablelen, uint32);
  207. serout.delay_table = NULL;
  208. }
  209. luaL_argcheck(L, platform_gpio_exists(serout.pin), 1, "Invalid pin");
  210. luaL_argcheck(L, serout.level==HIGH || serout.level==LOW, 2, "Wrong level type" );
  211. luaL_argcheck(L, lua_istable( L, 3 ) &&
  212. ((serout.tablelen = lua_objlen( L, 3 )) < DELAY_TABLE_MAX_LEN), 3, "Invalid delay_times" );
  213. serout.delay_table = luaM_newvector(L, serout.tablelen, uint32);
  214. for(unsigned i = 0; i < serout.tablelen; i++ ) {
  215. lua_rawgeti( L, 3, i + 1 );
  216. unsigned delay = (unsigned) luaL_checkinteger( L, -1 );
  217. serout.delay_table[i] = delay;
  218. lua_pop( L, 1 );
  219. }
  220. if (is_async) { // async version for duration above 15 mSec
  221. if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) {
  222. // Failed to init the timer
  223. luaL_error(L, "Unable to initialize timer");
  224. }
  225. platform_hw_timer_set_func(TIMER_OWNER, seroutasync_cb, 0);
  226. serout.index = 0;
  227. seroutasync_cb(0);
  228. } else { // sync version for sub-50 µs resolution & total duration < 15 mSec
  229. do {
  230. for( serout.index = 0;serout.index < serout.tablelen; serout.index++ ){
  231. NODE_DBG("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", serout.repeats, serout.index, serout.level, serout.pin, serout.tablelen, serout.delay_table[serout.index], system_get_time()); // timings is delayed for short timings when debug output is enabled
  232. GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[serout.pin]), serout.level);
  233. serout.level = serout.level==LOW ? HIGH : LOW;
  234. delayMicroseconds(serout.delay_table[serout.index]);
  235. }
  236. } while (serout.repeats--);
  237. luaM_freearray(L, serout.delay_table, serout.tablelen, uint32);
  238. }
  239. return 0;
  240. }
  241. #undef DELAY_TABLE_MAX_LEN
  242. // Module function map
  243. static const LUA_REG_TYPE gpio_map[] = {
  244. { LSTRKEY( "mode" ), LFUNCVAL( lgpio_mode ) },
  245. { LSTRKEY( "read" ), LFUNCVAL( lgpio_read ) },
  246. { LSTRKEY( "write" ), LFUNCVAL( lgpio_write ) },
  247. { LSTRKEY( "serout" ), LFUNCVAL( lgpio_serout ) },
  248. #ifdef GPIO_INTERRUPT_ENABLE
  249. { LSTRKEY( "trig" ), LFUNCVAL( lgpio_trig ) },
  250. { LSTRKEY( "INT" ), LNUMVAL( INTERRUPT ) },
  251. #endif
  252. { LSTRKEY( "OUTPUT" ), LNUMVAL( OUTPUT ) },
  253. { LSTRKEY( "OPENDRAIN" ), LNUMVAL( OPENDRAIN ) },
  254. { LSTRKEY( "INPUT" ), LNUMVAL( INPUT ) },
  255. { LSTRKEY( "HIGH" ), LNUMVAL( HIGH ) },
  256. { LSTRKEY( "LOW" ), LNUMVAL( LOW ) },
  257. { LSTRKEY( "FLOAT" ), LNUMVAL( FLOAT ) },
  258. { LSTRKEY( "PULLUP" ), LNUMVAL( PULLUP ) },
  259. { LNILKEY, LNILVAL }
  260. };
  261. int luaopen_gpio( lua_State *L ) {
  262. #ifdef GPIO_INTERRUPT_ENABLE
  263. int i;
  264. for(i=0;i<GPIO_PIN_NUM;i++){
  265. gpio_cb_ref[i] = LUA_NOREF;
  266. }
  267. platform_gpio_init(task_get_id(gpio_intr_callback_task));
  268. #endif
  269. serout.done_taskid = task_get_id((task_callback_t) seroutasync_done);
  270. serout.lua_done_ref = LUA_NOREF;
  271. return 0;
  272. }
  273. NODEMCU_MODULE(GPIO, "gpio", gpio_map, luaopen_gpio);