luat_lib_fota.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. @module fota
  3. @summary 底层固件升级
  4. @version core V0007
  5. @date 2022.05.26
  6. @demo fota
  7. @tag LUAT_USE_FOTA
  8. @usage
  9. -- 如果是从http获取升级包, 那么看demo/fota就可以了
  10. -- 以下是从其他途径获取更新包后, 调用本fota库的基本逻辑
  11. -- 逐段传入
  12. sys.taskInit(function()
  13. fota.init()
  14. while 1 do
  15. local buf = xxx -- 这里是从其他途径获取的升级包片段
  16. -- buf 可以是zbuff 也可以是string
  17. -- 每次写入的数据长度最大不应超过4k
  18. local result, isDone, cache = fota.run(buf)
  19. if not result then
  20. log.info("fota", "出错了")
  21. break
  22. end
  23. if isDone then
  24. while true do
  25. local succ,fotaDone = fota.isDone()
  26. if not succ then
  27. log.info("fota", "出错了")
  28. break
  29. end
  30. if fotaDone then
  31. log.info("fota", "已完成")
  32. break
  33. end
  34. sys.wait(100)
  35. end
  36. break
  37. end
  38. sys.wait(100)
  39. end
  40. end)
  41. -- 使用文件一次性传入
  42. sys.taskInit(function()
  43. fota.init()
  44. fota.file("/xxx") -- 传入具体的路径
  45. end)
  46. */
  47. #include "luat_base.h"
  48. #include "luat_fota.h"
  49. #include "luat_zbuff.h"
  50. #include "luat_spi.h"
  51. #include "luat_fs.h"
  52. #include "luat_mem.h"
  53. #define LUAT_LOG_TAG "fota"
  54. #include "luat_log.h"
  55. /**
  56. 初始化fota流程
  57. @api fota.init(storge_location, len, param1, param2)
  58. @int/string fota数据存储的起始位置<br>如果是int,则是由芯片平台具体判断<br>如果是string,则存储在文件系统中<br>如果为nil,则由底层决定存储位置
  59. @int 数据存储的最大空间
  60. @userdata param1,如果数据存储在spiflash时,为spi_device
  61. @int param2,目前只用于外部flash更新时, spiflash电源控制脚
  62. @return boolean 成功返回true, 失败返回false
  63. @usage
  64. -- 初始化fota流程
  65. local result = fota.init(0, 0x00300000, spi_device) --由于105的flash从0x01000000开始,所以0就是外部spiflash
  66. local result = fota.init() --Air780EXXX系列使用固定内部地址,所以不需要参数了
  67. local result = fota.init(0xe0000000, 0, spi_device, 27) --EC7XX系列允许使用外部flash更新,但是地址必须加上0xe0000000的偏移
  68. */
  69. static int l_fota_init(lua_State* L)
  70. {
  71. uint32_t address = 0xffffffff;
  72. size_t len = 0;
  73. uint32_t length;
  74. const char *buf = NULL;
  75. luat_spi_device_t* spi_device = NULL;
  76. if (lua_type(L, 1) == LUA_TSTRING)
  77. {
  78. buf = lua_tolstring(L, 1, &len);//取出字符串数据
  79. }
  80. else
  81. {
  82. address = luaL_optinteger(L, 1, 0xffffffff);
  83. }
  84. length = luaL_optinteger(L, 2, 0);
  85. if (lua_isuserdata(L, 3))
  86. {
  87. spi_device = (luat_spi_device_t*)lua_touserdata(L, 3);
  88. }
  89. uint8_t power_pin = luaL_optinteger(L, 4, 0xffffffff);
  90. if (spi_device)
  91. {
  92. spi_device->user_data = &power_pin;
  93. }
  94. lua_pushboolean(L, !luat_fota_init(address, length, spi_device, buf, len));
  95. return 1;
  96. }
  97. /**
  98. 等待底层fota流程准备好
  99. @api fota.wait()
  100. @return boolean 是否完整走完流程,true 表示正确走完流程了
  101. @usage
  102. local isDone = fota.wait()
  103. */
  104. static int l_fota_wait(lua_State* L)
  105. {
  106. lua_pushboolean(L, luat_fota_wait_ready());
  107. return 1;
  108. }
  109. /**
  110. 写入fota数据
  111. @api fota.run(buff, offset, len)
  112. @zbuff/string fota数据,尽量用zbuff
  113. @int 起始偏移量,传入zbuff时有效,默认是0
  114. @int 写入长度,传入zbuff时有效,默认是zbuff:used()
  115. @return boolean 有异常返回false,无异常返回true
  116. @return boolean 接收到最后一块返回true
  117. @return int 还未写入的数据量,超过64K必须做等待
  118. @usage
  119. local result, isDone, cache = fota.run(buf) -- 写入fota流程
  120. -- 提示: ,如果传入的是zbuff,写入成功后,请自行清空zbuff内的数据
  121. -- 2024.4.3新增offset, len参数, 仅对zbuff有效
  122. fota.run(buff, 0, 1024)
  123. */
  124. static int l_fota_write(lua_State* L)
  125. {
  126. int result = 0;
  127. size_t len = 0;
  128. const char *buf = NULL;
  129. if(lua_isuserdata(L, 1))
  130. {
  131. luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 1, LUAT_ZBUFF_TYPE));
  132. size_t offset = luaL_optinteger(L, 2, 0);
  133. len = luaL_optinteger(L, 3, buff->used - offset);
  134. if (len + offset > buff->len) {
  135. LLOGE("len too long %d > %d", len, buff->len);
  136. result = -1;
  137. }
  138. else {
  139. result = luat_fota_write(buff->addr + offset, len);
  140. }
  141. }
  142. else
  143. {
  144. buf = lua_tolstring(L, 1, &len);//取出字符串数据
  145. result = luat_fota_write((uint8_t*)buf, len);
  146. }
  147. if (result > 0)
  148. {
  149. lua_pushboolean(L, 1);
  150. lua_pushboolean(L, 0);
  151. }
  152. else if (result == 0)
  153. {
  154. lua_pushboolean(L, 1);
  155. lua_pushboolean(L, 1);
  156. }
  157. else
  158. {
  159. lua_pushboolean(L, 0);
  160. lua_pushboolean(L, 1);
  161. }
  162. lua_pushinteger(L, result);
  163. return 3;
  164. }
  165. /**
  166. 从指定文件读取fota数据
  167. @api fota.file(path)
  168. @string 文件路径
  169. @return boolean 有异常返回false,无异常返回true
  170. @return boolean 接收到最后一块返回true
  171. @return int 还未写入的数据量,超过64K必须做等待
  172. @usage
  173. local result, isDone, cache = fota.file("/xxx.bin") -- 写入fota流程
  174. -- 本API于2023.03.23 添加
  175. */
  176. static int l_fota_file(lua_State* L)
  177. {
  178. int result = 0;
  179. const char *path = luaL_checkstring(L, 1);
  180. FILE* fd = luat_fs_fopen(path, "rb");
  181. if (fd == NULL) {
  182. LLOGE("no such file for FOTA %s", path);
  183. lua_pushboolean(L, 0);
  184. lua_pushboolean(L, 0);
  185. lua_pushinteger(L, 0);
  186. return 3;
  187. }
  188. #define BUFF_SIZE (4096)
  189. char *buff = luat_heap_malloc(BUFF_SIZE);
  190. if (buff == NULL) {
  191. luat_fs_fclose(fd);
  192. LLOGE("out of memory when reading file %s", path);
  193. lua_pushboolean(L, 0);
  194. lua_pushboolean(L, 0);
  195. lua_pushinteger(L, 0);
  196. return 3;
  197. }
  198. int len = 0;
  199. while (1) {
  200. len = luat_fs_fread(buff , BUFF_SIZE, 1, fd);
  201. if (len < 1) {
  202. // EOF 结束了
  203. break;
  204. }
  205. result = luat_fota_write((uint8_t*)buff, len);
  206. if (result < 0) {
  207. break;
  208. }
  209. }
  210. luat_heap_free(buff);
  211. luat_fs_fclose(fd);
  212. if (result > 0)
  213. {
  214. lua_pushboolean(L, 1);
  215. lua_pushboolean(L, 0);
  216. }
  217. else if (result == 0)
  218. {
  219. lua_pushboolean(L, 1);
  220. lua_pushboolean(L, 1);
  221. }
  222. else
  223. {
  224. lua_pushboolean(L, 0);
  225. lua_pushboolean(L, 1);
  226. }
  227. lua_pushinteger(L, result);
  228. return 3;
  229. }
  230. /**
  231. 等待底层fota流程完成
  232. @api fota.isDone()
  233. @return boolean 有异常返回false,无异常返回true
  234. @return boolean 写入到最后一块返回true
  235. @usage
  236. local result, isDone = fota.isDone()
  237. */
  238. static int l_fota_done(lua_State* L)
  239. {
  240. int result = luat_fota_done();
  241. if (result > 0)
  242. {
  243. lua_pushboolean(L, 1);
  244. lua_pushboolean(L, 0);
  245. }
  246. else if (result == 0)
  247. {
  248. lua_pushboolean(L, 1);
  249. lua_pushboolean(L, 1);
  250. }
  251. else
  252. {
  253. lua_pushboolean(L, 0);
  254. lua_pushboolean(L, 1);
  255. }
  256. return 2;
  257. }
  258. /**
  259. 结束fota流程
  260. @api fota.finish(is_ok)
  261. @boolean 是否完整走完流程,true 表示正确走完流程了
  262. @return boolean 成功返回true, 失败返回false
  263. @usage
  264. -- 结束fota流程
  265. local result = fota.finish(true)
  266. */
  267. static int l_fota_end(lua_State* L)
  268. {
  269. lua_pushboolean(L, !luat_fota_end(lua_toboolean(L, 1)));
  270. return 1;
  271. }
  272. #include "rotable2.h"
  273. static const rotable_Reg_t reg_fota[] =
  274. {
  275. { "init", ROREG_FUNC(l_fota_init)},
  276. { "wait", ROREG_FUNC(l_fota_wait)},
  277. { "run", ROREG_FUNC(l_fota_write)},
  278. { "isDone", ROREG_FUNC(l_fota_done)},
  279. { "finish", ROREG_FUNC(l_fota_end)},
  280. { "file", ROREG_FUNC(l_fota_file)},
  281. { NULL, ROREG_INT(0) }
  282. };
  283. LUAMOD_API int luaopen_fota( lua_State *L ) {
  284. luat_newlib2(L, reg_fota);
  285. return 1;
  286. }