luat_lib_io_queue.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. @module ioqueue
  3. @summary io序列操作,配合硬件定时器力求达到us级,甚至更高
  4. @version 1.0
  5. @date 2022.03.13
  6. */
  7. #include "luat_base.h"
  8. #include "luat_multimedia.h"
  9. #include "luat_msgbus.h"
  10. #include "luat_zbuff.h"
  11. #define LUAT_LOG_TAG "io_queue"
  12. #include "luat_log.h"
  13. int l_io_queue_done_handler(lua_State *L, void* ptr)
  14. {
  15. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  16. lua_pop(L, 1);
  17. lua_getglobal(L, "sys_pub");
  18. lua_pushfstring(L, "IO_QUEUE_DONE_%d", msg->ptr);
  19. lua_call(L, 1, 0);
  20. return 1;
  21. }
  22. int l_io_queue_capture_handler(lua_State *L, void* ptr)
  23. {
  24. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  25. lua_getglobal(L, "sys_pub");
  26. LLOGD("%d", msg->arg1);
  27. lua_pushfstring(L, "IO_QUEUE_DONE_%d", msg->arg1);
  28. lua_call(L, 1, 0);
  29. return 1;
  30. }
  31. /*
  32. 初始化一个io操作队列
  33. @api ioqueue.init(hwtimer_id,cmd_cnt,repeat_cnt)
  34. @int 硬件定时器id,默认用0,根据实际MCU确定,air105为0~5,与pwm共用,同一个通道号不能同时为pwm和ioqueue
  35. @int 一个完整周期需要的命令,可以比实际的多
  36. @int 重复次数,默认是1,如果写0则表示无限次数循环
  37. @return 无
  38. @usage
  39. ioqueue.init(0,10,5) --以timer0为时钟源初始化一个io操作队列,有10个有效命令,循环5次
  40. */
  41. static int l_io_queue_init(lua_State *L) {
  42. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  43. int cmd_cnt = luaL_optinteger(L, 2, 0);
  44. int repeat_cnt = luaL_optinteger(L, 3, 1);
  45. luat_io_queue_init(timer_id, cmd_cnt, repeat_cnt);
  46. return 0;
  47. }
  48. /*
  49. 对io操作队列增加延时命令
  50. @api ioqueue.setdelay(hwtimer_id,time_us,time_tick,continue)
  51. @int 硬件定时器id
  52. @int 延时时间,0~65535us
  53. @int 延时微调时间,0~255tick,总的延时时间是time_us * 1us_tick + time_tick
  54. @boolean 是否连续是连续延时,默认否,如果是,定时器在时间到后不会停止而是重新计时,
  55. 从而实现在下一个setdelay命令前,每次调用delay都会重复相同时间延时,提高连续定时的精度
  56. @return 无
  57. @usage
  58. ioqueue.setdelay(0,10,0) --延时10us+0个tick
  59. ioqueue.setdelay(0,9,15,true) --延时9us+15个tick,在之后遇到delay命令时,会延时9us+15个tick
  60. */
  61. static int l_io_queue_set_delay(lua_State *L) {
  62. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  63. uint16_t us_delay = luaL_optinteger(L, 2, 1);
  64. uint8_t us_delay_tick = luaL_optinteger(L, 3, 0);
  65. uint8_t is_continue = 0;
  66. if (lua_isboolean(L, 4))
  67. {
  68. is_continue = lua_toboolean(L, 4);
  69. }
  70. luat_io_queue_set_delay(timer_id, us_delay, us_delay_tick, is_continue);
  71. return 0;
  72. }
  73. /*
  74. 对io操作队列增加一次重复延时,在前面必须有setdelay且是连续延时
  75. @api ioqueue.delay(hwtimer_id)
  76. @int 硬件定时器id
  77. @return 无
  78. @usage
  79. ioqueue.setdelay(0,9,15,true) --延时9us+15个tick,在之后遇到delay命令时,会延时9us+15个tick
  80. ioqueue.delay(0)
  81. */
  82. static int l_io_queue_delay(lua_State *L) {
  83. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  84. luat_io_queue_repeat_delay(timer_id);
  85. return 0;
  86. }
  87. /*
  88. 对io操作队列增加设置gpio命令
  89. @api ioqueue.setgpio(hwtimer_id,pin,is_input,pull_mode,init_level)
  90. @int 硬件定时器id
  91. @int pin
  92. @boolean 是否是输入
  93. @int 上下拉模式,只能是0,gpio.PULLUP,gpio.PULLDOWN
  94. @int 初始输出电平
  95. @return 无
  96. @usage
  97. ioqueue.setgpio(0,pin.PB01,true,gpio.PULLUP,0) --PB01设置成上拉输入
  98. ioqueue.setgpio(0,pin.PB01,false,0,1)--PB01设置成上拉输出高电平
  99. */
  100. static int l_io_queue_set_gpio(lua_State *L) {
  101. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  102. uint8_t pin = luaL_checkinteger(L, 2);
  103. uint8_t pull_mode = luaL_optinteger(L, 4, 0);
  104. uint8_t init_level = luaL_optinteger(L, 5, 0);
  105. uint8_t is_input = 0;
  106. if (lua_isboolean(L, 3))
  107. {
  108. is_input = lua_toboolean(L, 3);
  109. }
  110. luat_io_queue_add_io_config(timer_id, pin, is_input, pull_mode, init_level);
  111. return 0;
  112. }
  113. /*
  114. 对io操作队列增加读取gpio命令
  115. @api ioqueue.input(hwtimer_id,pin)
  116. @int 硬件定时器id
  117. @int pin
  118. @return 无
  119. @usage
  120. ioqueue.input(0,pin.PB01)
  121. */
  122. static int l_io_queue_gpio_input(lua_State *L) {
  123. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  124. uint8_t pin = luaL_checkinteger(L, 2);
  125. luat_io_queue_add_io_in(timer_id, pin, NULL, NULL);
  126. return 0;
  127. }
  128. /*
  129. 对io操作队列增加输出GPIO命令
  130. @api ioqueue.output(hwtimer_id,pin,level)
  131. @int 硬件定时器id
  132. @int pin
  133. @int 输出电平
  134. @return 无
  135. @usage
  136. ioqueue.output(0,pin.PB01,0)
  137. */
  138. static int l_io_queue_gpio_output(lua_State *L) {
  139. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  140. uint8_t pin = luaL_checkinteger(L, 2);
  141. uint8_t level = luaL_optinteger(L, 3, 0);
  142. luat_io_queue_add_io_out(timer_id, pin, level);
  143. return 0;
  144. }
  145. /*
  146. 对io操作队列增加设置捕获某个IO命令
  147. @api ioqueue.setcap(hwtimer_id,pin,pull_mode,irq_mode,max_tick)
  148. @int 硬件定时器id
  149. @int pin
  150. @int 上下拉模式,只能是0,gpio.PULLUP,gpio.PULLDOWN
  151. @int 中断模式,只能是gpio.BOTH,gpio.RISING,gpio.FALLING
  152. @int 定时器最大计时时间 考虑到lua是int类型,最小0x10000, 最大值为0x7fffffff,默认为最大值
  153. @return 无
  154. @usage
  155. ioqueue.setcap(0,pin.PB01,gpio.PULLUP,gpio.FALLING,48000000)
  156. */
  157. static int l_io_queue_set_capture(lua_State *L) {
  158. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  159. uint8_t pin = luaL_checkinteger(L, 2);
  160. uint8_t pull_mode = luaL_optinteger(L, 3, 0);
  161. uint8_t irq_mode = luaL_optinteger(L, 4, 0);
  162. int max_cnt = luaL_optinteger(L, 5, 0x7fffffff);
  163. if (max_cnt < 65536)
  164. {
  165. max_cnt = 65536;
  166. }
  167. luat_io_queue_capture_set(timer_id, max_cnt, pin, pull_mode, irq_mode);
  168. return 0;
  169. }
  170. /*
  171. 对io操作队列增加捕获一次IO状态命令
  172. @api ioqueue.capture(hwtimer_id)
  173. @int 硬件定时器id
  174. @return 无
  175. @usage
  176. ioqueue.capture(0)
  177. */
  178. static int l_io_queue_capture_pin(lua_State *L) {
  179. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  180. luat_io_queue_capture(timer_id, NULL, NULL);
  181. return 0;
  182. }
  183. /*
  184. 对io操作队列增加结束捕获某个IO命令
  185. @api ioqueue.capend(hwtimer_id,pin)
  186. @int 硬件定时器id
  187. @int pin
  188. @return 无
  189. @usage
  190. ioqueue.capend(0,pin.PB01)
  191. */
  192. static int l_io_queue_capture_end(lua_State *L) {
  193. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  194. uint8_t pin = luaL_checkinteger(L, 2);
  195. luat_io_queue_capture_end(timer_id, pin);
  196. return 0;
  197. }
  198. /*
  199. * 获取io操作队列中输入和捕获的数据
  200. @api ioqueue.get(hwtimer_id, input_buff, capture_buff)
  201. @int 硬件定时器id
  202. @zbuff 存放IO输入数据的buff,按照1byte pin + 1byte level 形式存放数据
  203. @zbuff 存放IO捕获数据的buff,按照1byte pin + 1byte level + 4byte tick形式存放数据
  204. @return int 返回多少组IO输入数据 int 返回多少组IO捕获数据
  205. @usage
  206. local input_cnt, capture_cnt = ioqueue.get(0, input_buff, capture_buff)
  207. */
  208. static int l_io_queue_get(lua_State *L) {
  209. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  210. luat_zbuff_t *buff1 = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  211. luat_zbuff_t *buff2 = ((luat_zbuff_t *)luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE));
  212. uint32_t input_cnt, capture_cnt;
  213. uint32_t size = luat_io_queue_get_size(timer_id);
  214. if (buff1->len < (size * 2)) __zbuff_resize(buff1, (size * 2));
  215. if (buff2->len < (size * 6)) __zbuff_resize(buff2, (size * 6));
  216. luat_io_queue_get_data(timer_id, buff1->addr, &input_cnt, buff2->addr, &capture_cnt);
  217. buff1->used = input_cnt * 2;
  218. buff2->used = capture_cnt * 6;
  219. lua_pushinteger(L, input_cnt);
  220. lua_pushinteger(L, capture_cnt);
  221. return 2;
  222. }
  223. /*
  224. 启动io操作队列
  225. @api ioqueue.start(hwtimer_id)
  226. @int 硬件定时器id
  227. @return 无
  228. @usage
  229. ioqueue.start(0)
  230. */
  231. static int l_io_queue_start(lua_State *L) {
  232. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  233. luat_io_queue_start(timer_id);
  234. return 0;
  235. }
  236. /*
  237. 停止io操作队列,可以通过start从头开始
  238. @api ioqueue.stop(hwtimer_id)
  239. @int 硬件定时器id
  240. @return 无
  241. @usage
  242. ioqueue.stop(0)
  243. */
  244. static int l_io_queue_stop(lua_State *L) {
  245. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  246. luat_io_queue_stop(timer_id);
  247. return 0;
  248. }
  249. /*
  250. 释放io操作队列的资源,下次使用必须重新init
  251. @api ioqueue.release(hwtimer_id)
  252. @int 硬件定时器id
  253. @return 无
  254. @usage
  255. ioqueue.clear(0)
  256. */
  257. static int l_io_queue_release(lua_State *L) {
  258. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  259. luat_io_queue_release(timer_id);
  260. return 0;
  261. }
  262. /*
  263. 清空io操作队列
  264. @api ioqueue.clear(hwtimer_id)
  265. @int 硬件定时器id
  266. @return 无
  267. @usage
  268. ioqueue.clear(0)
  269. */
  270. static int l_io_queue_clear(lua_State *L) {
  271. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  272. luat_io_queue_clear(timer_id);
  273. return 0;
  274. }
  275. /*
  276. 检测io操作队列是否已经执行完成
  277. @api ioqueue.done(hwtimer_id)
  278. @int 硬件定时器id
  279. @return boolean 队列是否执行完成,
  280. @usage
  281. local result = ioqueue.done(0)
  282. */
  283. static int l_io_queue_is_done(lua_State *L) {
  284. uint8_t timer_id = luaL_optinteger(L, 1, 0);
  285. lua_pushboolean(L, luat_io_queue_check_done(timer_id));
  286. return 1;
  287. }
  288. /*
  289. 启动/停止一个带系统tick返回的外部中断
  290. @api ioqueue.exti(pin,pull_mode,irq_mode,onoff)
  291. @int pin
  292. @int 上下拉模式,只能是0,gpio.PULLUP,gpio.PULLDOWN
  293. @int 中断模式,只能是gpio.BOTH,gpio.RISING,gpio.FALLING
  294. @boolean 开关,默认是false关
  295. @return 无
  296. @usage
  297. ioqueue.exti(pin.PB01, gpio.PULLUP, gpio.BOTH, true)
  298. ioqueue.exti(pin.PB01)
  299. */
  300. static int l_io_queue_exti(lua_State *L) {
  301. uint8_t pin = luaL_checkinteger(L, 1);
  302. uint8_t pull_mode = luaL_optinteger(L, 2, 0);
  303. uint8_t irq_mode = luaL_optinteger(L, 3, 0);
  304. uint8_t on_off = 0;
  305. if (lua_isboolean(L, 4)) {
  306. on_off = lua_toboolean(L, 4);
  307. }
  308. if (on_off) {
  309. luat_io_queue_capture_start_with_sys_tick(pin, pull_mode, irq_mode);
  310. } else {
  311. luat_io_queue_capture_end_with_sys_tick(pin);
  312. }
  313. return 0;
  314. }
  315. #include "rotable2.h"
  316. static const rotable_Reg_t reg_io_queue[] =
  317. {
  318. { "init" , ROREG_FUNC(l_io_queue_init)},
  319. { "setdelay" , ROREG_FUNC(l_io_queue_set_delay)},
  320. { "delay" , ROREG_FUNC(l_io_queue_delay)},
  321. { "setgpio", ROREG_FUNC(l_io_queue_set_gpio)},
  322. { "input", ROREG_FUNC(l_io_queue_gpio_input)},
  323. { "output", ROREG_FUNC(l_io_queue_gpio_output)},
  324. { "set_cap", ROREG_FUNC(l_io_queue_set_capture)},
  325. { "capture", ROREG_FUNC(l_io_queue_capture_pin)},
  326. { "cap_done", ROREG_FUNC(l_io_queue_capture_end)},
  327. { "clear", ROREG_FUNC(l_io_queue_clear)},
  328. { "start", ROREG_FUNC(l_io_queue_start)},
  329. { "stop", ROREG_FUNC(l_io_queue_stop)},
  330. { "done", ROREG_FUNC(l_io_queue_is_done)},
  331. { "get", ROREG_FUNC(l_io_queue_get)},
  332. { "release", ROREG_FUNC(l_io_queue_release)},
  333. { "exti", ROREG_FUNC(l_io_queue_exti)},
  334. { NULL, {}}
  335. };
  336. LUAMOD_API int luaopen_io_queue( lua_State *L ) {
  337. luat_newlib2(L, reg_io_queue);
  338. return 1;
  339. }