FOTA升级
一、FOTA 介绍
FOTA 即远程升级功能,此功能可以让客户在不方便大量线刷升级(设备不在身边/量产 PCB 没引出 USB/需要大批量进行功能升级)的情况下,快速进行底层固件/脚本/脚本 + 底层固件的远程更新。
LuatOS 开发模式下,固件分为两部分:core 和 script
远程升级时:升级 script 和 core+script 为全量覆盖升级
远程升级时:可以仅升级 script;也可以同时升级 core+script
支持合宙 iot 平台升级和自建第三方服务器(HTTP)升级
二、演示功能概述
本 demo 教你怎么使用 LuatOS 脚本语言,就可以让 Air8101 开发板实现远程升级。
三、准备硬件环境
“古人云:‘工欲善其事,必先利其器。’在深入介绍本功能示例之前,我们首先需要确保以下硬件环境的准备工作已经完成。”
参考:硬件环境清单,准备以及组装好硬件环境。
四、软件环境
“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。
- Luatools 工具;
- 内核固件文件(底层 core 固件文件):LuatOS-SoC_V10001_Air8101.soc;参考项目使用的内核固件;
- luatos 需要的脚本和资源文件
脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/FOTA
lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。
五、 合宙自有服务器 FOTA 简介
5.1 云平台配置
使用合宙自建服务器的话,需要先登录合宙 IOT 平台,如下图所示,没有账号的,可以先注册一个 客户向合宙采购 4G 模块时,如果采购人员没有告知合宙这批模块放在 iot.openluat.com 上的哪个产品下,则合宙会以采购人的手机号为账号,默认密码 888888,创建一个“AirXX 标准模块”的项目,此次采购的所有模块都会放在这个项目下,如果你的账号下没有对应 imei,可以联系合宙销售帮忙添加模块进对应项目下(最好还是从哪里买的模块,就让他给你转移到你自己名下)
登录以后点击红框所示位置
然后依次点击如下图所示红框所示的地方,创建一个新项目
在所有项目的最后,找到自己刚刚新建的项目,并且点击红框内的"查看/点击复制"复制后面升级所需要的校验码,复制到自己剪切板中。代码中需要填写。
PRODUCT_KEY = "q01f89YFOFYxluL05jMI6aiIlKJy1SYA"
至此,合宙云平台上的预备动作就做完了
5.2 仅升级脚本
5.2.1 远程升级文件制作
打开 Luatools 的项目管理界面,点击生成量产文件,纯脚本升级文件放在 luatools 根目录下的"SOC 量产及远程升级文件\Air8101"目录下
生成文件如下
因为模块烧录的是 001.000.000 版本,所以我们需要给脚本里的版本号改一下,改为 001.000.001 版本
再将脚本中增加几行打印(为了模拟用户修改脚本的动作)
然后重新生成一次量产固件
修改文件名称为:fotademo_001.000.001_LuatOS-SoC_V0002_Air8101.bin
打开刚刚的合宙 iot 平台点击固件升级--我的固件--创建固件
点击选择文件,把刚刚的 bin 后缀文件上传到 iot 平台
文件名、固件名、版本号都是自动识别的,用户无需修改
点击确定,等待上传成功的动画提示
上传完成界面
5.2.2 指定设备
模块刚开机,luatools 会打印模块的 STA MAC 号,如下图所示,为 C8478CB8242E 记录下来
在刚刚创建固件的地方,点击指定设备按钮,如下图所示
然后按下图所示,添加模块的 imei,注意这里填写 STA MAC 号,即 C8478CB8242E 。
添加完成如图所示
5.2.3 重启设备开始远程升级
启动设备检查升级包
升级中:模块请求升级,下载完升级包以后会进行 MD5 验证升级包有无问题,如果没问题,就会启动重启程序,然后进行升级工作
升级完成的日志
5.3 同时升级 core+script
每一次 core 的升级都会带来一些网络上的优化(例如信号差时的网络稳定性)以及一些 bug 修复,所以在发布新版本以后,用户可以先测试下 core 对自己脚本有无明显影响或性能提升,然后进行远程 FOTA
使用的 DEMO 程序与仅升级脚本的程序相同,直接使用即可。
设计的固件如下所示,具体生成方法参见 5.2.1 中
由于 V10002 已经本文写作时最新版本的 core 了,所以为了演示方便,001.000.000 脚本选择搭配的 core 为 V10001 版本,点击"下载底层和脚本"
添加固件
点击确定如下图所示
更新固件后重启,开始远程升级
升级完成自动重启设备
六、代码示例介绍
6.1 API 介绍
软件 API 参考 https://docs.openluat.com/air780e/luatos/api/ext/libfota2/
libfota.request(cbFnc, opts)
fota 升级
参数
**传入值类型** | **解释** |
table | fota参数 |
function | cbFnc 用户回调函数,回调函数的调用形式为:cbFnc(result) , 必须传 |
返回值
**返回值类型** | **解释** |
nil | 无返回值 |
例子
无
6.2 核心脚本代码详解
6.2.1 系统初始化与联网
该部分代码尝试通过 Wi-Fi 连接到指定的 SSID 和密码。如果设备支持 Wi-Fi 并能成功连接,会等待 Wi-Fi 网络连接成功并发布 net_ready 消息。
sys.taskInit(function()
if wlan and wlan.connect then
local ssid = "Xiaomi_1100"
local password = "1234567890"
wlan.init()
wlan.setMode(wlan.STATION)
wlan.connect(ssid, password, 1)
local result, data = sys.waitUntil("IP_READY")
device_id = wlan.getMac()
else
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp可能未适配网络层, 请查证")
end
end
sys.publish("net_ready")
end)
6.2.2 版本号打印
该部分代码每 5 秒打印一次当前的脚本版本号和底层操作系统(rtos.version())的版本号。这对于调试和查看版本更新是否正常有帮助。
sys.taskInit(function()
while 1 do
sys.wait(5000)
log.info("fota", "脚本版本号", VERSION, "core版本号", rtos.version())
end
end)
6.2.3 FOTA 升级回调函数
该部分代码首先检查 PRODUCT_KEY 是否正确配置,如果不正确,则进入死循环提示用户修改正确的密钥。
然后,等待网络连接成功,开始检查是否有可用的 FOTA 升级。
libfota2.request(fota_cb, ota_opts) 触发 FOTA 升级请求,ota_opts 是 OTA 请求的配置参数。
local function fota_cb(ret)
log.info("fota", ret)
if ret == 0 then
log.info("升级包下载成功,重启模块")
rtos.reboot()
elseif ret == 1 then
log.info("连接失败", "请检查url拼写或服务器配置(是否为内网)")
elseif ret == 2 then
log.info("url错误", "检查url拼写")
elseif ret == 3 then
log.info("服务器断开", "检查服务器白名单配置")
elseif ret == 4 then
log.info("接收报文错误", "检查模块固件或升级包内文件是否正常")
elseif ret == 5 then
log.info("版本号书写错误", "iot平台版本号需要使用xxx.yyy.zzz形式")
else
log.info("不是上面几种情况 ret为",ret)
end
end
fota_cb 是 FOTA 请求的回调函数,根据返回值 ret 打印不同的日志信息。
0: 升级成功,触发设备重启。
1: 连接失败,提示检查 URL 拼写或服务器配置。
2: URL 错误,提示检查 URL 拼写。
3: 服务器断开,提示检查服务器的白名单配置。
4: 接收报文错误,提示检查模块固件或升级包文件是否正常。
5: 版本号错误,提示使用符合格式 xxx.yyy.zzz 的版本号。
OTA 升级请求与定时检查
lua
sys.taskInit(function()
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")
log.info("开始检查升级")
sys.wait(500)
libfota2.request(fota_cb, ota_opts)
end)
6.2.4 定时自动升级
该行代码通过 sys.timerLoopStart 设置每 4 小时自动检查一次升级。
sys.timerLoopStart(libfota2.request, 4 * 3600000, fota_cb, ota_opts)
6.3 完整程序清单
注:完整复制后保存为 main.lua,可直接使用
-- main.lua文件
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "fota_demo"
-- iot限制,只能上传xxx.yyy.zzz格式的三位数的版本号,但实际上现在只用了XXX和ZZZ,中间yyy暂未使用
-- 需要注意的是,因为yyy不生效,所以111.222.333版本和111.444.333版本,对iot平台来说都一样,所以建议中间那一位永远写000
VERSION = "001.000.000"
-- 使用合宙iot平台时需要这个参数
PRODUCT_KEY = "q01f89YFOFYxluL05jMI6aiIlKJy1SYA" -- 到 iot.openluat.com 创建项目,获取正确的项目key(刚刚剪切板里的校验码就填这里)
sys = require "sys"
libfota2 = require "libfota2"
-- 联网函数, 可自行删减
sys.taskInit(function()
-----------------------------
-- 统一联网函数, 可自行删减
----------------------------
if wlan and wlan.connect then
-- wifi 联网, Air8101系列均支持
local ssid = "Xiaomi_1100"
local password = "1234567890"
log.info("wifi", ssid, password)
wlan.init()
wlan.setMode(wlan.STATION)
wlan.connect(ssid, password, 1)
--等待WIFI联网结果,WIFI联网成功后,内核固件会产生一个"IP_READY"消息
local result, data = sys.waitUntil("IP_READY")
log.info("wlan", "IP_READY", result, data)
device_id = wlan.getMac()
else
-- 其他不认识的bsp, 循环提示一下吧
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp可能未适配网络层, 请查证")
end
end
log.info("已联网")
sys.publish("net_ready")
end)
-- 循环打印版本号, 方便看版本号变化, 非必须
sys.taskInit(function()
while 1 do
sys.wait(5000)
log.info("降功耗,找合宙")
log.info("fota", "脚本版本号", VERSION, "core版本号", rtos.version())
end
end)
-- 升级结果的回调函数
-- 功能:获取fota的回调函数
-- 参数:
-- result:number类型
-- 0表示成功
-- 1表示连接失败
-- 2表示url错误
-- 3表示服务器断开
-- 4表示接收报文错误
-- 5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
local function fota_cb(ret)
log.info("fota", ret)
if ret == 0 then
log.info("升级包下载成功,重启模块")
rtos.reboot()
elseif ret == 1 then
log.info("连接失败", "请检查url拼写或服务器配置(是否为内网)")
elseif ret == 2 then
log.info("url错误", "检查url拼写")
elseif ret == 3 then
log.info("服务器断开", "检查服务器白名单配置")
elseif ret == 4 then
log.info("接收报文错误", "检查模块固件或升级包内文件是否正常")
elseif ret == 5 then
log.info("版本号书写错误", "iot平台版本号需要使用xxx.yyy.zzz形式")
else
log.info("不是上面几种情况 ret为",ret)
end
end
-- 使用合宙iot平台进行升级,不需要管下面这段代码
-- 使用第三方服务器时打开下面这段代码
local ota_opts = {
--url = "",
-- 合宙IOT平台的默认升级URL, 不填就是这个默认值
-- 如果是自建的OTA服务器, 则需要填写正确的URL, 例如 http://192.168.1.5:8000/update
-- 如果自建OTA服务器,且url包含全部参数,不需要额外添加参数, 请在url前面添加 ###
-- 如果不加###,则默认会上传如下参数
-- 1. opts.version string 版本号, 默认是 BSP版本号.x.z格式
-- 2. opts.timeout int 请求超时时间, 默认300000毫秒,单位毫秒
-- 3. opts.project_key string 合宙IOT平台的项目key, 默认取全局变量PRODUCT_KEY. 自建服务器不用填
-- 4. opts.imei string 设备识别码, 默认取IMEI(Cat.1模块)或WLAN MAC地址(wifi模块)或MCU唯一ID
-- 5. opts.firmware_name string 底层版本号
-- 请求的版本号, 合宙IOT有一套版本号体系,不传就是合宙规则, 自建服务器的话当然是自行约定版本号了
--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")
log.info("开始检查升级")
sys.wait(500)
libfota2.request(fota_cb, ota_opts)
end)
-- 演示定时自动升级, 每隔4小时自动检查一次
sys.timerLoopStart(libfota2.request, 4 * 3600000, fota_cb, ota_opts)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
七、 总结
至此,我们已使用 Air8101 开发板完成了远程升级的基本功能。