ota_demo.lua 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. -- 用http方式下载ota固件并实现升级
  2. -- 注意下载速度比写flash速度要快的多,而ram有限,w5500目前无法控制下载速度,所以需要先擦除flash,预估一定时间后,才能开始下载
  3. --[[
  4. -- 这个是用uart3直接把升级包发给mcu,作为本地升级的一种参考,高速串口单次发送不要超过4K
  5. local rbuff = zbuff.create(16384)
  6. local function uartRx(id, len)
  7. uart.rx(id, rbuff)
  8. if rbuff:used() > 0 then
  9. local isError,fotaDone,nCache = fota.run(rbuff)
  10. if not isError then
  11. else
  12. log.error("fota写入异常,请至少在1秒后重试")
  13. fota.finish(false)
  14. return
  15. end
  16. rbuff:del()
  17. -- log.info("收到服务器数据,长度", rbuff:used(), "fota结果", isError, done, "总共", filelen)
  18. if fotaDone then
  19. log.info("下载完成")
  20. sys.publish("downloadOK")
  21. end
  22. end
  23. end
  24. local function otaTask()
  25. local spiFlash = spi.deviceSetup(spi.SPI_1,pin.PA7,0,0,8,24*1000*1000,spi.MSB,1,1)
  26. fota.init(0, 0x00200000, spiFlash)
  27. while not fota.wait() do
  28. sys.wait(100)
  29. end
  30. uart.setup(3,1500000)
  31. uart.on(3, "receive", uartRx)
  32. uart.write(3,"ready")
  33. sys.waitUntil("downloadOK")
  34. while true do
  35. local isError,fotaDone = fota.isDone()
  36. if fotaDone then
  37. fota.finish(true)
  38. log.info("FOTA完成")
  39. rtos.reboot() --如果还有其他事情要做,就不要立刻reboot
  40. break
  41. end
  42. sys.wait(100)
  43. end
  44. end
  45. function otaDemo()
  46. sys.taskInit(otaTask)
  47. end
  48. ]]
  49. local libnet = require "libnet"
  50. local taskName = "OTA_TASK"
  51. local function netCB(msg)
  52. log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
  53. end
  54. local function otaTask()
  55. local spiFlash = spi.deviceSetup(spi.SPI_1,pin.PA7,0,0,8,24*1000*1000,spi.MSB,1,1)
  56. fota.init(0, 0x00200000, spiFlash)
  57. while not fota.wait() do
  58. sys.wait(100)
  59. end
  60. -- 如果确定只下载脚本,可以下载到文件系统里
  61. -- fota.init("/update.bin", 0, nil)
  62. -- os.remove("/update.bin")
  63. local isError, param, ip, port, total, findhead, filelen, rcvCache,d1,d2,statusCode,retry,rspHead,rcvChunked,done,fotaDone,nCache
  64. local tbuff = zbuff.create(512)
  65. local rbuff = zbuff.create(2048)
  66. local netc = network.create(network.ETH0, taskName)
  67. network.config(netc, nil, nil, nil) -- http用的普通TCP连接
  68. -- 用的iot平台,用芯片名称+24byte id(实际上是12byte,96bit)
  69. -- 当然也可以用自己设置的id规则
  70. local imei,_ = mcu.unique_id():toHex()
  71. imei = rtos.bsp() .. string.sub(imei, 9, 32)
  72. log.info(imei, rtos.firmware())
  73. filelen = 0
  74. total = 0
  75. retry = 0
  76. done = false
  77. rspHead = {}
  78. local result = libnet.waitLink(taskName, 0, netc)
  79. while retry < 3 and not done do
  80. result = libnet.connect(taskName, 5000, netc, "iot.openluat.com", 80) --后续出了http库则直接用http来处理
  81. tbuff:del()
  82. -- 用的iot平台,所以固件名称和版本号需要对应处理
  83. -- 用的自建平台,可以自主定制规则
  84. local v = rtos.version()
  85. v = tonumber(v:sub(2, 5))
  86. tbuff:copy(0, "GET /api/site/firmware_upgrade?project_key=" .. _G.PRODUCT_KEY .. "&imei=".. imei .. "&device_key=&firmware_name=" .. _G.PROJECT.. "_LuatOS-SoC_" .. rtos.bsp() .. "&version=" .. v .. "." .. _G.VERSION .. " HTTP/1.1\r\n")
  87. tbuff:copy(nil,"Host: iot.openluat.com:80\r\n")
  88. if filelen > 0 then --断网重连的话,只需要下载剩余的部分就行了
  89. tbuff:copy(nil,"Range: bytes=" .. total .. "-\r\n")
  90. end
  91. tbuff:copy(nil,"Accept: application/octet-stream\r\n\r\n")
  92. log.info(tbuff:query())
  93. result = libnet.tx(taskName, 5000, netc, tbuff)
  94. rbuff:del()
  95. findhead = false
  96. while result do
  97. isError, param, ip, port = network.rx(netc, rbuff)
  98. if isError then
  99. log.info("服务器断开了", isError, param, ip, port)
  100. break
  101. end
  102. if rbuff:used() > 0 then
  103. if findhead then
  104. isError,fotaDone,nCache = fota.run(rbuff)
  105. if not isError then
  106. total = total + rbuff:used()
  107. else
  108. log.error("fota写入异常,请至少在1秒后重试")
  109. fota.finish(false)
  110. done = true
  111. break
  112. end
  113. rbuff:del()
  114. -- log.info("收到服务器数据,长度", rbuff:used(), "fota结果", isError, done, "总共", filelen)
  115. if fotaDone then
  116. log.info("下载完成")
  117. while true do
  118. isError,fotaDone = fota.isDone()
  119. if fotaDone then
  120. fota.finish(true)
  121. log.info("FOTA完成")
  122. done = true
  123. rtos.reboot() --如果还有其他事情要做,就不要立刻reboot
  124. break
  125. end
  126. sys.wait(100)
  127. end
  128. break
  129. end
  130. else
  131. rcvCache = rbuff:query()
  132. d1,d2 = rcvCache:find("\r\n\r\n")
  133. -- 打印出http response head
  134. -- log.info(rcvCache:sub(1, d2))
  135. if d2 then
  136. --状态行
  137. _,d1,statusCode = rcvCache:find("%s(%d+)%s.-\r\n")
  138. if not statusCode then
  139. log.info("http没有状态返回")
  140. break
  141. end
  142. statusCode = tonumber(statusCode)
  143. if statusCode ~= 200 and statusCode ~= 206 then
  144. log.info("http应答不OK", statusCode)
  145. done = true
  146. break
  147. end
  148. --应答头
  149. for k,v in string.gmatch(rcvCache:sub(d1+1,d2-2),"(.-):%s*(.-)\r\n") do
  150. rspHead[k] = v
  151. if (string.upper(k)==string.upper("Transfer-Encoding")) and (string.upper(v)==string.upper("chunked")) then rcvChunked = true end
  152. end
  153. if filelen == 0 and not rcvChunked then
  154. if not rcvChunked then
  155. filelen = tonumber(rspHead["Content-Length"] or "2147483647")
  156. end
  157. end
  158. --未处理的body数据
  159. rbuff:del(0, d2)
  160. isError,fotaDone,nCache = fota.run(rbuff)
  161. if not isError then
  162. total = total + rbuff:used()
  163. else
  164. log.error("fota写入异常,请至少在1秒后重试")
  165. fota.finish(false)
  166. done = true
  167. break
  168. end
  169. rbuff:del()
  170. -- log.info("收到服务器数据,长度", rbuff:used(), "fota结果", isError, done, "总共", filelen)
  171. else
  172. break
  173. end
  174. findhead = true
  175. end
  176. end
  177. result, param = libnet.wait(taskName, 5000, netc)
  178. if not result then
  179. log.info("服务器断开了", result, param)
  180. break
  181. elseif not param then
  182. log.info("服务器没有数据", result, param)
  183. break
  184. end
  185. end
  186. libnet.close(taskName, 5000, netc)
  187. retry = retry + 1
  188. end
  189. network.release(netc)
  190. sysplus.taskDel(taskName)
  191. fota.finish(false)
  192. end
  193. function otaDemo()
  194. sysplus.taskInitEx(otaTask, taskName, netCB)
  195. end