luat_lib_gpio.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. @module gpio
  3. @summary GPIO操作
  4. @catalog 外设API
  5. @version 1.0
  6. @date 2020.03.30
  7. @demo gpio
  8. @video https://www.bilibili.com/video/BV1hr4y1p7dt
  9. */
  10. #include "luat_base.h"
  11. #include "luat_gpio.h"
  12. #include "luat_malloc.h"
  13. #define LUAT_LOG_TAG "gpio"
  14. #include "luat_log.h"
  15. static int l_gpio_set(lua_State *L);
  16. static int l_gpio_get(lua_State *L);
  17. static int l_gpio_close(lua_State *L);
  18. #ifdef LUAT_GPIO_NUMS
  19. #define GPIO_IRQ_COUNT LUAT_GPIO_NUMS
  20. #else
  21. #define GPIO_IRQ_COUNT 16
  22. #endif
  23. typedef struct luat_lib_gpio_cb
  24. {
  25. int pin;
  26. int lua_ref;
  27. } luat_lib_gpio_cb_t;
  28. // 保存中断回调的数组
  29. static luat_lib_gpio_cb_t irq_cbs[GPIO_IRQ_COUNT];
  30. static uint8_t default_gpio_pull = Luat_GPIO_DEFAULT;
  31. // 记录GPIO电平,仅OUTPUT时可用
  32. #define PIN_MAX (128)
  33. static uint8_t gpio_out_levels[PIN_MAX / 8] = {0};
  34. static uint8_t gpio_bit_get(int pin) {
  35. if (pin < 0 || pin >= PIN_MAX)
  36. return 0;
  37. return (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
  38. }
  39. static void gpio_bit_set(int pin, uint8_t value) {
  40. if (pin < 0 || pin >= PIN_MAX)
  41. return;
  42. uint8_t val = (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
  43. if (val == value)
  44. return; // 不变呀
  45. if (value == 0) {
  46. gpio_out_levels[pin/8] -= (1 << (pin%8));
  47. }
  48. else {
  49. gpio_out_levels[pin/8] += (1 << (pin%8));
  50. }
  51. }
  52. int l_gpio_handler(lua_State *L, void* ptr) {
  53. // 给 sys.publish方法发送数据
  54. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  55. int pin = msg->arg1;
  56. for (size_t i = 0; i < GPIO_IRQ_COUNT; i++)
  57. {
  58. if (irq_cbs[i].pin == pin) {
  59. lua_geti(L, LUA_REGISTRYINDEX, irq_cbs[i].lua_ref);
  60. if (!lua_isnil(L, -1)) {
  61. lua_pushinteger(L, msg->arg2);
  62. lua_call(L, 1, 0);
  63. }
  64. return 0;
  65. }
  66. }
  67. return 0;
  68. }
  69. /*
  70. 设置管脚功能
  71. @api gpio.setup(pin, mode, pull, irq)
  72. @int pin 针脚编号,必须是数值
  73. @any mode 输入输出模式. 数字0/1代表输出模式,nil代表输入模式,function代表中断模式
  74. @int pull 上拉下列模式, 可以是gpio.PULLUP 或 gpio.PULLDOWN, 需要根据实际硬件选用
  75. @int irq 默认gpio.BOTH。中断触发模式, 上升沿gpio.RISING, 下降沿gpio.FALLING, 上升和下降都要gpio.BOTH
  76. @return any 输出模式返回设置电平的闭包, 输入模式和中断模式返回获取电平的闭包
  77. @usage
  78. -- 设置gpio17为输入
  79. gpio.setup(17, nil)
  80. -- 设置gpio17为输出
  81. gpio.setup(17, 0)
  82. -- 设置gpio27为中断
  83. gpio.setup(27, function(val) print("IRQ_27",val) end, gpio.PULLUP)
  84. */
  85. static int l_gpio_setup(lua_State *L) {
  86. luat_gpio_t conf;
  87. conf.pin = luaL_checkinteger(L, 1);
  88. //conf->mode = luaL_checkinteger(L, 2);
  89. conf.lua_ref = 0;
  90. conf.irq = 0;
  91. if (lua_isfunction(L, 2)) {
  92. conf.mode = Luat_GPIO_IRQ;
  93. lua_pushvalue(L, 2);
  94. conf.lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  95. conf.irq = luaL_optinteger(L, 4, Luat_GPIO_BOTH);
  96. }
  97. else if (lua_isinteger(L, 2)) {
  98. conf.mode = Luat_GPIO_OUTPUT;
  99. conf.irq = luaL_checkinteger(L, 2) == 0 ? 0 : 1; // 重用irq当初始值用
  100. }
  101. else {
  102. conf.mode = Luat_GPIO_INPUT;
  103. }
  104. conf.pull = luaL_optinteger(L, 3, default_gpio_pull);
  105. conf.irq_cb = 0;
  106. int re = luat_gpio_setup(&conf);
  107. if (re == 0) {
  108. if (conf.mode == Luat_GPIO_IRQ) {
  109. int flag = 1;
  110. for (size_t i = 0; i < GPIO_IRQ_COUNT; i++) {
  111. if (irq_cbs[i].pin == conf.pin) {
  112. if (irq_cbs[i].lua_ref && irq_cbs[i].lua_ref != conf.lua_ref) {
  113. luaL_unref(L, LUA_REGISTRYINDEX, irq_cbs[i].lua_ref);
  114. irq_cbs[i].lua_ref = conf.lua_ref;
  115. }
  116. flag = 0;
  117. break;
  118. }
  119. if (irq_cbs[i].pin == -1) {
  120. irq_cbs[i].pin = conf.pin;
  121. irq_cbs[i].lua_ref = conf.lua_ref;
  122. flag = 0;
  123. break;
  124. }
  125. }
  126. if (flag) {
  127. LLOGE("luat.gpio", "too many irq setup!!!!");
  128. re = 1;
  129. luat_gpio_close(conf.pin);
  130. }
  131. }
  132. else if (conf.mode == Luat_GPIO_OUTPUT) {
  133. luat_gpio_set(conf.pin, conf.irq); // irq被重用为OUTPUT的初始值
  134. }
  135. }
  136. // 生成闭包包
  137. if (re != 0) {
  138. return 0;
  139. }
  140. lua_settop(L, 1);
  141. if (conf.mode == Luat_GPIO_OUTPUT) {
  142. lua_pushcclosure(L, l_gpio_set, 1);
  143. }
  144. else {
  145. lua_pushcclosure(L, l_gpio_get, 1);
  146. }
  147. return 1;
  148. }
  149. /*
  150. 设置管脚电平
  151. @api gpio.set(pin, value)
  152. @int pin 针脚编号,必须是数值
  153. @int value 电平, 可以是 高电平gpio.HIGH, 低电平gpio.LOW, 或者直接写数值1或0
  154. @return nil 无返回值
  155. @usage
  156. -- 设置gpio17为低电平
  157. gpio.set(17, 0)
  158. */
  159. static int l_gpio_set(lua_State *L) {
  160. int pin = 0;
  161. int value = 0;
  162. if (lua_isinteger(L, lua_upvalueindex(1))) {
  163. pin = lua_tointeger(L, lua_upvalueindex(1));
  164. value = luaL_checkinteger(L, 1);
  165. }
  166. else {
  167. pin = luaL_checkinteger(L, 1);
  168. value = luaL_checkinteger(L, 2);
  169. }
  170. luat_gpio_set(pin, value);
  171. gpio_bit_set(pin, (uint8_t)value);
  172. return 0;
  173. }
  174. /*
  175. 获取管脚电平
  176. @api gpio.get(pin)
  177. @int pin 针脚编号,必须是数值
  178. @return value 电平, 高电平gpio.HIGH, 低电平gpio.LOW, 对应数值1和0
  179. @usage
  180. -- 获取gpio17的当前电平
  181. gpio.get(17)
  182. */
  183. static int l_gpio_get(lua_State *L) {
  184. if (lua_isinteger(L, lua_upvalueindex(1)))
  185. lua_pushinteger(L, luat_gpio_get(luaL_checkinteger(L, lua_upvalueindex(1))) & 0x01 ? 1 : 0);
  186. else
  187. lua_pushinteger(L, luat_gpio_get(luaL_checkinteger(L, 1)) & 0x01 ? 1 : 0);
  188. return 1;
  189. }
  190. /*
  191. 关闭管脚功能(高阻输入态),关掉中断
  192. @api gpio.close(pin)
  193. @int pin 针脚编号,必须是数值
  194. @return nil 无返回值,总是执行成功
  195. @usage
  196. -- 关闭gpio17
  197. gpio.close(17)
  198. */
  199. static int l_gpio_close(lua_State *L) {
  200. int pin = luaL_checkinteger(L, 1);
  201. luat_gpio_close(pin);
  202. for (size_t i = 0; i < GPIO_IRQ_COUNT; i++) {
  203. if (irq_cbs[i].pin == pin) {
  204. irq_cbs[i].pin = -1;
  205. if (irq_cbs[i].lua_ref) {
  206. luaL_unref(L, LUA_REGISTRYINDEX, irq_cbs[i].lua_ref);
  207. irq_cbs[i].lua_ref = 0;
  208. }
  209. }
  210. }
  211. return 0;
  212. }
  213. /*
  214. 设置GPIO脚的默认上拉/下拉设置, 默认是平台自定义(一般为开漏).
  215. @api gpio.setDefaultPull(val)
  216. @int val 0平台自定义,1上拉, 2下拉
  217. @return boolean 传值正确返回true,否则返回false
  218. @usage
  219. -- 设置gpio.setup的pull默认值为上拉
  220. gpio.setDefaultPull(1)
  221. */
  222. static int l_gpio_set_default_pull(lua_State *L) {
  223. int value = luaL_checkinteger(L, 1);
  224. if (value >= 0 && value <= 2) {
  225. default_gpio_pull = value;
  226. lua_pushboolean(L, 1);
  227. }
  228. else {
  229. lua_pushboolean(L, 0);
  230. }
  231. return 1;
  232. }
  233. /*
  234. 变换GPIO脚输出电平,仅输出模式可用
  235. @api gpio.toggle(pin)
  236. @int 管脚的GPIO0AB4276E.png
  237. @return nil 无返回值
  238. @usage
  239. -- 本API于 2022.05.17 添加
  240. -- 假设GPIO16上有LED, 每500ms切换一次开关
  241. gpio.setup(16, 0)
  242. sys.timerLoopStart(function()
  243. gpio.toggle(16)
  244. end, 500)
  245. */
  246. static int l_gpio_toggle(lua_State *L) {
  247. int pin = 0;
  248. if (lua_isinteger(L, lua_upvalueindex(1)))
  249. pin = lua_tointeger(L, lua_upvalueindex(1));
  250. else
  251. pin = luaL_checkinteger(L, 1);
  252. if (pin < 0 || pin >= PIN_MAX) {
  253. LLOGD("pin id out of range (0-127)");
  254. return 0;
  255. }
  256. uint8_t value = gpio_bit_get(pin);
  257. luat_gpio_set(pin, value == 0 ? Luat_GPIO_HIGH : Luat_GPIO_LOW);
  258. gpio_bit_set(pin, value == 0 ? 1 : 0);
  259. return 0;
  260. }
  261. /*
  262. 在同一个GPIO输出一组脉冲, 注意, len的单位是bit, 高位在前.
  263. @api gpio.pulse(pin,level,len,delay)
  264. @int gpio号
  265. @int/string 数值或者字符串.
  266. @int len 长度 单位是bit, 高位在前.
  267. @int delay 延迟,当前无固定时间单位
  268. @return nil 无返回值
  269. @usage
  270. -- 通过PB06脚输出输出8个电平变化.
  271. gpio.pulse(pin.PB06,0xA9, 8, 0)
  272. */
  273. static int l_gpio_pulse(lua_State *L) {
  274. int pin,delay = 0;
  275. size_t len;
  276. char* level = NULL;
  277. if (lua_isinteger(L, lua_upvalueindex(1))){
  278. pin = lua_tointeger(L, lua_upvalueindex(1));
  279. if (lua_isinteger(L, 1)){
  280. *level = (char)luaL_checkinteger(L, 1);
  281. }else if (lua_isstring(L, 1)){
  282. level = (char*)luaL_checklstring(L, 1, &len);
  283. }
  284. len = luaL_checkinteger(L, 2);
  285. delay = luaL_checkinteger(L, 3);
  286. }else{
  287. pin = luaL_checkinteger(L, 1);
  288. if (lua_isinteger(L, 2)){
  289. *level = (char)luaL_checkinteger(L, 2);
  290. }else if (lua_isstring(L, 2)){
  291. level = (char*)luaL_checklstring(L, 2, &len);
  292. }
  293. len = luaL_checkinteger(L, 3);
  294. delay = luaL_checkinteger(L, 4);
  295. }
  296. if (pin < 0 || pin >= PIN_MAX) {
  297. LLOGD("pin id out of range (0-127)");
  298. return 0;
  299. }
  300. luat_gpio_pulse(pin,(uint8_t*)level,len,delay);
  301. return 0;
  302. }
  303. #include "rotable2.h"
  304. static const rotable_Reg_t reg_gpio[] =
  305. {
  306. { "setup" , ROREG_FUNC(l_gpio_setup )},
  307. { "set" , ROREG_FUNC(l_gpio_set)},
  308. { "get" , ROREG_FUNC(l_gpio_get)},
  309. { "close" , ROREG_FUNC(l_gpio_close)},
  310. { "toggle", ROREG_FUNC(l_gpio_toggle)},
  311. { "setDefaultPull", ROREG_FUNC(l_gpio_set_default_pull)},
  312. #ifndef LUAT_COMPILER_NOWEAK
  313. { "pulse", ROREG_FUNC(l_gpio_pulse)},
  314. #endif
  315. { "LOW", ROREG_INT(Luat_GPIO_LOW)},
  316. { "HIGH", ROREG_INT(Luat_GPIO_HIGH)},
  317. { "OUTPUT", ROREG_INT(Luat_GPIO_OUTPUT)},
  318. { "INPUT", ROREG_INT(Luat_GPIO_INPUT)},
  319. { "IRQ", ROREG_INT(Luat_GPIO_IRQ)},
  320. { "PULLUP", ROREG_INT(Luat_GPIO_PULLUP)},
  321. { "PULLDOWN", ROREG_INT(Luat_GPIO_PULLDOWN)},
  322. { "RISING", ROREG_INT(Luat_GPIO_RISING)},
  323. { "FALLING", ROREG_INT(Luat_GPIO_FALLING)},
  324. { "BOTH", ROREG_INT(Luat_GPIO_BOTH)},
  325. { NULL, ROREG_INT(0) }
  326. };
  327. LUAMOD_API int luaopen_gpio( lua_State *L ) {
  328. // int i;
  329. for (size_t i = 0; i < GPIO_IRQ_COUNT; i++) {
  330. irq_cbs[i].pin = -1;
  331. }
  332. luat_newlib2(L, reg_gpio);
  333. return 1;
  334. }
  335. // -------------------- 一些辅助函数
  336. void luat_gpio_mode(int pin, int mode, int pull, int initOutput) {
  337. if (pin == 255) return;
  338. luat_gpio_t conf = {0};
  339. conf.pin = pin;
  340. conf.mode = mode == Luat_GPIO_INPUT ? Luat_GPIO_INPUT : Luat_GPIO_OUTPUT; // 只能是输入/输出, 不能是中断.
  341. conf.pull = pull;
  342. conf.irq = initOutput;
  343. conf.lua_ref = 0;
  344. conf.irq_cb = 0;
  345. luat_gpio_setup(&conf);
  346. if (conf.mode == Luat_GPIO_OUTPUT)
  347. luat_gpio_set(pin, initOutput);
  348. }
  349. #ifndef LUAT_COMPILER_NOWEAK
  350. void LUAT_WEAK luat_gpio_pulse(int pin, uint8_t *level, uint16_t len, uint16_t delay_ns) {
  351. }
  352. #endif