uartTaskTest.lua 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. --- 模块功能:串口1功能测试
  2. -- @author openLuat
  3. -- @module uart.testUart
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2018.03.27
  7. module(...,package.seeall)
  8. require "utils"
  9. require "pm"
  10. require "sys"
  11. require "log"
  12. --[[
  13. 功能定义:
  14. uart按照帧结构接收外围设备的输入,收到正确的指令后,回复ASCII字符串
  15. 帧结构如下:
  16. 帧头:1字节,0x01表示扫描指令,0x02表示控制GPIO命令,0x03表示控制端口命令
  17. 帧体:字节不固定,跟帧头有关
  18. 帧尾:1字节,固定为0xC0
  19. 收到的指令帧头为0x01时,回复"CMD_SCANNER\r\n"给外围设备;例如接收到0x01 0xC0两个字节,就回复"CMD_SCANNER\r\n"
  20. 收到的指令帧头为0x02时,回复"CMD_GPIO\r\n"给外围设备;例如接收到0x02 0xC0两个字节,就回复"CMD_GPIO\r\n"
  21. 收到的指令帧头为0x03时,回复"CMD_PORT\r\n"给外围设备;例如接收到0x03 0xC0两个字节,就回复"CMD_PORT\r\n"
  22. 收到的指令帧头为其余数据时,回复"CMD_ERROR\r\n"给外围设备;例如接收到0x04 0xC0两个字节,就回复"CMD_ERROR\r\n"
  23. ]]
  24. --串口ID,1对应uart1
  25. --如果要修改为uart2,把UART_ID赋值为2即可
  26. local UART_ID = 1
  27. --帧头以及帧尾
  28. local FRM_HEAD,FRM_TAIL = 0xaa55,0x0d0a
  29. --rfid 去重缓存的超时时间
  30. local rfid_buffer_timeout = 20
  31. local rfid_buffer_max_count = 100
  32. --串口读到的数据缓冲区
  33. local rdbuf = ""
  34. require "misc"
  35. local function getTime()
  36. local tm = misc.getClock()
  37. return string.format("%04d/%02d/%02d,%02d:%02d:%02d", tm.year, tm.month, tm.day, tm.hour, tm.min, tm.sec)
  38. end
  39. --初始化rfid缓冲池
  40. local start_time = os.time()
  41. local rfids_buf = {["start_time"]=start_time,["rfid_count"]=0,["buf"]={}}
  42. --require "HashMap"
  43. --local rfid_map = HashMap:new()
  44. local function parse_rfid(body)
  45. if not body then return false end
  46. if body:len() ~= 9 then
  47. log.info("parse_rfid fail,body.length != 9")
  48. return false
  49. end
  50. local id = string.sub(body,1,6):toHex()
  51. local type = tonumber(string.byte(body,7))
  52. local status = tonumber(string.byte(body,8))
  53. local rssi = tonumber(string.byte(body,9))
  54. local rfid = {["id"]=id,["type"]=type,["status"]=status,["rssi"]=rssi}
  55. return rfid
  56. end
  57. --[[
  58. 函数名:parse
  59. 功能 :按照帧结构解析处理一条完整的帧数据
  60. 参数 :
  61. data:所有未处理的数据
  62. 返回值:第一个返回值是一条完整帧报文的处理结果,第二个返回值是未处理的数据
  63. ]]
  64. local function parse(data)
  65. if not data then return end
  66. if data:len() < 14 then return end
  67. local frm_head = tonumber(string.format( "%02x",string.byte(data,1)) .. string.format( "%02x",string.byte(data,2)),16)
  68. local tail = string.find(data,string.char(0x0d)..string.char(0x0a))
  69. if not tail then
  70. log.info("end char:0x0d0a not found,wait for more ... ", data:toHex())
  71. return false,data
  72. end
  73. if frm_head ~= FRM_HEAD then
  74. log.info("FRM_HEAD ERROR,drop it, frm_head = ", frm_head, ", FRM_HEAD = ", FRM_HEAD)
  75. return false,string.sub(data,tail+2,-1)
  76. end
  77. local frm_len = tonumber(string.byte(data,3))
  78. local body,result = string.sub(data,4,tail-1)
  79. --检测body完整性
  80. if (frm_len-2) ~= body:len() then
  81. log.info("frm body length error, frm_len-2 = ",frm_len-2,", body:len() = ", body:len(), ", body:toHex() = ", body:toHex())
  82. return false,string.sub(data,tail+2,-1)
  83. end
  84. --log.info("uart1Task.parse",data:toHex(),frm_head,body:toHex())
  85. --解析rfid
  86. local rfid_info = parse_rfid(body)
  87. if not rfid_info then
  88. log.info("parse_rfid() failed!")
  89. return false,string.sub(data,tail+2,-1)
  90. end
  91. --检测到超时时,发布数据并重置 rfids_buf
  92. local cur_time = os.time()
  93. if (cur_time - rfids_buf.start_time >= rfid_buffer_timeout) or (rfids_buf.rfid_count >= rfid_buffer_max_count) then
  94. if rfids_buf.rfid_count > 0 then
  95. --log.info(">>>>>>> uartTaskTest.parse pub_packet_data", cur_time, rfids_buf.rfid_count)
  96. sys.publish("pub_packet_data", rfids_buf)
  97. end
  98. rfids_buf = {["start_time"]=cur_time,["rfid_count"]=0,["buf"]={}}
  99. end
  100. --新增数据
  101. if not rfids_buf["buf"][rfid_info.id] then
  102. --log.info(">>>>>>> push rfid to buf,rfid:", rfid_info.id)
  103. rfids_buf.rfid_count = rfids_buf.rfid_count + 1
  104. rfids_buf["buf"][rfid_info.id] = {["time"]=cur_time,["recv_count"]=1,["rssi"]=rfid_info.rssi,["type"]=rfid_info.type,["status"]=rfid_info.status}
  105. return true,string.sub(data,tail+2,-1)
  106. end
  107. --更新数据
  108. local recv_count = rfids_buf["buf"][rfid_info.id]["recv_count"] + 1
  109. rfids_buf["buf"][rfid_info.id] = {["time"]=cur_time,["recv_count"]=recv_count,["rssi"]=rfid_info.rssi,["type"]=rfid_info.type,["status"]=rfid_info.status}
  110. --log.info(">>>>>>> update rfid_buf,rfid:", rfid_info.id, ", recv_count:", recv_count)
  111. return true,string.sub(data,tail+2,-1)
  112. end
  113. --[[
  114. 函数名:proc
  115. 功能 :处理从串口读到的数据
  116. 参数 :
  117. data:当前一次从串口读到的数据
  118. 返回值:无
  119. ]]
  120. local function proc(data)
  121. if not data or string.len(data) == 0 then return end
  122. --追加到缓冲区
  123. rdbuf = rdbuf..data
  124. local result,unproc
  125. unproc = rdbuf
  126. --根据帧结构循环解析未处理过的数据
  127. while true do
  128. result,unproc = parse(unproc)
  129. if not unproc or unproc == "" or not result then
  130. break
  131. end
  132. end
  133. rdbuf = unproc or ""
  134. end
  135. --[[
  136. 函数名:read
  137. 功能 :读取串口接收到的数据
  138. 参数 :无
  139. 返回值:无
  140. ]]
  141. local function read()
  142. local data = ""
  143. --底层core中,串口收到数据时:
  144. --如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据;
  145. --如果接收缓冲器不为空,则不会通知Lua脚本
  146. --所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出,这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点
  147. while true do
  148. data = uart.read(UART_ID,"*l")
  149. if not data or string.len(data) == 0 then break end
  150. --打开下面的打印会耗时
  151. log.info("testUart.read bin",data)
  152. --log.info("testUart.read hex",data:toHex())
  153. --处理串口收到的rfid数据
  154. proc(data)
  155. end
  156. end
  157. --[[
  158. 函数名:write
  159. 功能 :通过串口发送数据
  160. 参数 :
  161. s:要发送的数据
  162. 返回值:无
  163. ]]
  164. function write(s)
  165. log.info("testUart.write",s)
  166. uart.write(UART_ID,s.."\r\n")
  167. end
  168. local function writeOk()
  169. log.info("testUart.writeOk")
  170. end
  171. --检测 rfids_buf是否超时
  172. sys.timerLoopStart(function ()
  173. --log.info(">>>>>>> uart1Task.timerLoopStart ")
  174. --检测到超时时,发布数据并重置 rfids_buf
  175. local cur_time = os.time()
  176. if (cur_time - rfids_buf.start_time >= rfid_buffer_timeout) or (rfids_buf.rfid_count >= rfid_buffer_max_count) then
  177. if rfids_buf.rfid_count > 0 then
  178. --log.info(">>>>>>> uartTaskTest.timerLoopStart pub_packet_data", cur_time, rfids_buf.rfid_count)
  179. sys.publish("pub_packet_data", rfids_buf)
  180. end
  181. rfids_buf = {["start_time"]=cur_time,["rfid_count"]=0,["buf"]={}}
  182. end
  183. end, 100)
  184. --保持系统处于唤醒状态,此处只是为了测试需要,所以此模块没有地方调用pm.sleep("testUart")休眠,不会进入低功耗休眠状态
  185. --在开发“要求功耗低”的项目时,一定要想办法保证pm.wake("testUart")后,在不需要串口时调用pm.sleep("testUart")
  186. pm.wake("testUart")
  187. --注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据
  188. uart.on(UART_ID,"receive",read)
  189. --注册串口的数据发送通知函数
  190. uart.on(UART_ID,"sent",writeOk)
  191. --配置并且打开串口
  192. --波特率,可选1200,2400,4800,9600,10400,14400,19200,28800,38400,57600,115200,230400,460800,921600
  193. --uart.setup(UART_ID,921600,8,uart.PAR_NONE,uart.STOP_1)
  194. --uart.setup(UART_ID,460800,8,uart.PAR_NONE,uart.STOP_1)
  195. --如果需要打开“串口发送数据完成后,通过异步消息通知”的功能,则使用下面的这行setup,注释掉上面的一行setup
  196. uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1,nil,1)
  197. uart.set_rs485_oe(UART_ID, pio.P2_0) --仅4G 0013版本之后支持