Просмотр исходного кода

add: 添加libfota2库, 验证libfota/libfota2在Air601的兼容性, 均正常

Wendal Chen 1 год назад
Родитель
Сommit
776831c493
3 измененных файлов с 278 добавлено и 3 удалено
  1. 109 0
      demo/fota2/main.lua
  2. 8 3
      script/libs/libfota.lua
  3. 161 0
      script/libs/libfota2.lua

+ 109 - 0
demo/fota2/main.lua

@@ -0,0 +1,109 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fotademo"
+VERSION = "1.0.0"
+
+--[[
+本demo 适用于 任何支持 fota 功能的模块, 包括:
+1. Cat.1模块, 如: Air700E/Air600E/Air780E/Air780EP/Air780EPV
+2. wifi模块, 如: ESP32C3/ESP32S3/Air601
+3. 外挂以太网的模块, 例如 Air105 + W5500
+]]
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "123" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+sys = require "sys"
+libfota2 = require "libfota2"
+
+
+-- 统一联网函数, 可自行删减
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持, 要根据实际情况修改ssid和password!!
+        local ssid = "luatos1234"
+        local password = "12341234"
+        log.info("wifi", ssid, password)
+        -- TODO 改成自动配网
+        wlan.init()
+        wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
+        wlan.connect(ssid, password, 1)
+    elseif mobile then
+        -- EC618系列, 如Air780E/Air600E/Air700E
+        -- mobile.simid(2) -- 自动切换SIM卡, 按需启用
+        -- 模块默认会自动联网, 无需额外的操作
+    elseif w5500 then
+        -- w5500 以太网
+        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
+        w5500.config() --默认是DHCP模式
+        w5500.bind(socket.ETH0)
+    elseif socket then
+        -- 适配了socket库也OK, 就当1秒联网吧
+        sys.timerStart(sys.publish, 1000, "IP_READY")
+    else
+        -- 其他不认识的bsp, 循环提示一下吧
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp可能未适配网络层, 请查证")
+        end
+    end
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready")
+end)
+
+-- 循环打印版本号, 方便看版本号变化, 非必须
+sys.taskInit(function()
+    while 1 do
+        sys.wait(1000)
+        log.info("fota", "version", VERSION)
+    end
+end)
+
+-- 升级结果的回调函数
+local function fota_cb(ret)
+    log.info("fota", ret)
+    if ret == 0 then
+        rtos.reboot()
+    end
+end
+
+-- 使用合宙iot平台进行升级, 支持自定义参数, 也可以不配置
+local ota_opts = {
+    -- 合宙IOT平台的默认升级URL, 不填就是这个默认值
+    -- 如果是自建的OTA服务器, 则需要填写正确的URL, 例如 http://192.168.1.5:8000/update
+    -- 如果自建OTA服务器,且url包含全部参数,不需要额外添加参数, 请在url前面添加 ### 
+    -- url="http://iot.openluat.com/api/site/firmware_upgrade",
+    -- 请求的版本号, 合宙IOT有一套版本号体系,不传就是合宙规则, 自建服务器的话当然是自行约定版本号了
+    -- version=_G.VERSION,
+    -- 其他更多参数, 请查阅libfota2的文档 https://wiki.luatos.com/api/libs/libfota2.html
+}
+sys.taskInit(function()
+    -- 这个判断是提醒要设置PRODUCT_KEY的,实际生产请删除
+    if "123" == _G.PRODUCT_KEY and not ota_opts.url then
+        while 1 do
+            sys.wait(1000)
+            log.info("fota", "请修改正确的PRODUCT_KEY")
+        end
+    end
+    -- 等待网络就行后开始检查升级
+    sys.waitUntil("net_ready")
+    sys.wait(500)
+    libfota2.request(fota_cb, ota_opts)
+    --演示按键触发升级, 这里假定使用GPIO0进行触发
+    --sys.wait(1000)
+    --gpio.debounce(0, 3000, 1)
+    --gpio.setup(0, function()
+    --     libfota2.request(fota_cb, ota_opts)
+    --end, gpio.PULLUP)
+end)
+-- 演示定时自动升级, 每隔4小时自动检查一次
+sys.timerLoopStart(libfota2.request, 4*3600000, fota_cb, ota_opts)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 8 - 3
script/libs/libfota.lua

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2023.02.01
 @author  Dozingfiretruck
+@demo    fota
 @usage
 --注意:因使用了sys.wait()所有api需要在协程中使用
 --用法实例
@@ -85,10 +86,14 @@ local function fota_task(cbFnc,storge_location, len, param1,ota_url,ota_port,lib
         end
     end
     local ret
-    if server_cert then
-        
+    local opts = {timeout = libfota_timeout}
+    if fota then
+        opts.fota = true
+    else
+        opts.dst = "/update.bin"
     end
-    local code, headers, body = http.request("GET", ota_url, nil, nil, {fota=true,timeout = libfota_timeout},server_cert, client_cert, client_key, client_password).wait()
+    log.info("fota.url", ota_url)
+    local code, headers, body = http.request("GET", ota_url, nil, nil, opts, server_cert, client_cert, client_key, client_password).wait()
     log.info("http fota", code, headers, body)
     if code == 200 or code == 206 then
         if body == 0 then

+ 161 - 0
script/libs/libfota2.lua

@@ -0,0 +1,161 @@
+--[[
+@module libfota2
+@summary fota升级v2
+@version 1.0
+@date    2024.04.09
+@author  wendal
+@demo    fota2
+@usage
+--用法实例
+local libfota2 = require("libfota2")
+
+-- 功能:获取fota的回调函数
+-- 参数:
+-- result:number类型
+--   0表示成功
+--   1表示连接失败
+--   2表示url错误
+--   3表示服务器断开
+--   4表示接收报文错误
+--   5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
+function libfota_cb(result)
+    log.info("fota", "result", result)
+    -- fota成功
+    if result == 0 then
+        rtos.reboot()   --如果还有其他事情要做,自行决定reboot的时机
+    end
+end
+
+--下方示例为合宙iot平台,地址:http://iot.openluat.com 
+libfota2.request(libfota_cb)
+
+--如使用自建服务器,自行更换url
+-- 对自定义服务器的要求是:
+-- 若需要升级, 响应http 200, body为升级文件的内容
+-- 若不需要升级, 响应300或以上的代码,务必注意
+local opts = {url="http://xxxxxx.com/xxx/upgrade"}
+-- opts的详细说明, 看后面的函数API文档
+libfota2.request(libfota_cb, opts)
+
+-- 若需要定时升级
+-- 合宙iot平台
+sys.timerLoopStart(libfota2.request, 4*3600*1000, libfota_cb)
+-- 自建平台
+sys.timerLoopStart(libfota2.request, 4*3600*1000, libfota_cb, opts)
+]]
+
+local sys = require "sys"
+require "sysplus"
+
+local libfota2 = {}
+
+
+local function fota_task(cbFnc, opts)
+    local ret = 0
+    local code, headers, body = http.request(opts.method, opts.url, opts.headers, opts.body, opts, opts.server_cert, opts.client_cert, opts.client_key, opts.client_password).wait()
+    log.info("http fota", code, headers, body)
+    if code == 200 or code == 206 then
+        if body == 0 then
+            ret = 4
+        else
+            ret = 0
+        end
+    elseif code == -4 then
+        ret = 1
+    elseif code == -5 then
+        ret = 3
+    else
+        ret = 4
+    end
+    cbFnc(ret)
+end
+
+--[[
+fota升级
+@api libfota.request(cbFnc, opts)
+@table fota参数, 后面有详细描述
+@function cbFnc 用户回调函数,回调函数的调用形式为:cbFnc(result) , 必须传
+@return nil 无返回值
+@usaga
+
+-- opts参数说明, 所有参数都是可选的
+-- 1. opts.url string 升级所需要的URL, 若使用合宙iot平台,则不需要填
+-- 2. opts.version string 版本号, 默认是 BSP版本号.x.z格式
+-- 3. opts.timeout int 请求超时时间, 默认300000毫秒,单位毫秒
+-- 4. opts.project_key string 合宙IOT平台的项目key, 默认取全局变量PRODUCT_KEY. 自建服务器不用填
+-- 5. opts.imei string 设备识别码, 默认取IMEI(Cat.1模块)或WLAN MAC地址(wifi模块)或MCU唯一ID
+-- 6. opts.firmware_name string 固件名称,默认是 _G.PROJECT.. "_LuatOS-SoC_" .. rtos.bsp()
+-- 7. opts.server_cert string 服务器证书, 默认不使用
+-- 8. opts.client_cert string 客户端证书, 默认不使用
+-- 9. opts.client_key string 客户端私钥, 默认不使用
+-- 10. opts.client_password string 客户端私钥口令, 默认不使用
+-- 11. opts.method string 请求方法, 默认是GET
+-- 12. opts.headers table 额外添加的请求头,默认不需要
+-- 13. opts.body string 额外添加的请求body,默认不需要
+]]
+function libfota2.request(cbFnc, opts)
+    if not opts then
+        opts = {}
+    end
+    if fota then
+        opts.fota = true
+    else
+        opts.dst = "/update.bin"
+    end
+    if not cbFnc then
+        cbFnc = function() end
+    end
+    -- 处理URL
+    if not opts.url then
+        opts.url = "http://iot.openluat.com/api/site/firmware_upgrade"
+    end
+    if opts.url:sub(1, 4) ~= "###" then
+        -- 补齐project_key函数
+        if not opts.project_key then
+            opts.project_key = _G.PRODUCT_KEY
+            if not opts.project_key then
+                log.error("fota", "iot.openluat.com need PRODUCT_KEY!!!")
+                cbFnc(5)
+                return
+            end
+        end
+        -- 补齐version参数
+        if not opts.version then
+            local x,y,z = string.match(_G.VERSION,"(%d+).(%d+).(%d+)")
+            opts.version = rtos.version():sub(2) .. "." .. x.."."..z
+        end
+        -- 补齐firmware_name参数
+        if not opts.firmware_name then
+            opts.firmware_name = _G.PROJECT.. "_LuatOS-SoC_" .. rtos.bsp()
+        end
+        -- 补齐imei参数
+        if not opts.imei then
+            local imei = ""
+            if mobile then
+                imei = mobile.imei()
+            elseif wlan and wlan.getMac then
+                imei = wlan.getMac()
+            else
+                imei = mcu.unique_id():toHex()
+            end
+            opts.imei = imei
+        end
+
+        -- 然后拼接到最终的url里
+        opts.url = string.format("%s?imei=%s&project_key=%s&firmware_name=%s&version=%s", opts.url, opts.imei, opts.project_key, opts.firmware_name, opts.version)
+    else
+        opts.url = opts.url:sub(4)
+    end
+    -- 处理method
+    if not opts.method then
+        opts.method = "GET"
+    end
+    log.info("fota.url", opts.method, opts.url)
+    log.info("fota.imei", opts.imei)
+    log.info("fota.project_key", opts.project_key)
+    log.info("fota.firmware_name", opts.firmware_name)
+    log.info("fota.version", opts.version)
+    sys.taskInit(fota_task, cbFnc, opts)
+end
+
+return libfota2