基于LiteOS的OTA组件实现对终端固件的差分升级和全量升级
基于LiteOS的OTA组件升级
- 本文实现方式
- PCP协议
-
- 协议介绍
- 通讯方式
- LiteOS
- 实现效果
- QT上位机打包
- 差分包制作
-
- 安装python2.7
- 安装pycryptodome算法库
- 差分包制作
- 升级包制作
- 设备端具体实现
-
- 工程目录结构
- Flash相关
-
- App与Boot使用相同的Flash读写函数
- Flash分区
- App实现
- Boot实现
- Sota Info
- 其他说明
本文实现方式
本文中使用上位机(基于QT6)模拟华为云平台,上位机和设备之间使用PCP协议进行串口通讯,基于LiteOS的OTA组件实现对终端固件的差分升级和全量升级,终端设备在本地升级测试完成后,将通讯方式更改后就可以快速对接华为云平台。
PCP协议
协议介绍
平台升级协议(PCP协议)规定了设备和平台之间升级的通信内容与格式。协议规定设备和IoT平台(以下简称“平台”)之间的应用层升级协议(简称“PCP协议”),用于实现设备的升级。PCP协议消息由:起始标识位、版本号、消息码、校验码、数据区长度和数据区组成。
通讯方式
- PCP协议运行在应用层,底层可以是LwM2M/CoAP/MQTT或者其他非流式协议。
- 由于PCP协议消息没有使用单独的端口号,并且不依赖于底层协议,为了和设备业务消息区分,PCP协议固定以0XFFFE作为起始字节。因此要求设备的业务消息的前两个字节不能是0XFFFE。
- 本协议消息采用一问一答模式,所有请求消息都有一个响应消息。
LiteOS
Huawei LiteOS是华为面向物联网领域开发的一个基于实时内核的轻量级操作系统。
OTA组件路径:LiteOS-master\components\ota
实现效果
设备侧同时支持差分升级和全量升级。设备Application固件变化:
测试流程:
Step1:V1.0------>>差分------>>V1.1
上电:
升级结束:
Step2:V1.1------>>回滚------>>V1.0
Step3:V1.0------>>全量------>>V1.2
Step4:V1.2------>>回滚------>>V1.0
Step5:V1.0------>>差分------>>V1.2
QT上位机打包
- 将源码release编译版本(…\xxxxxx\build\Desktop_Qt_6_9_1_MinGW_64_bit-Release\release)下的exe文件复制到单独的文件夹。
- 在上一步文件夹下打开命令行工具。
- 使用QT安装目录下的windeployqt工具(D:\Qt\6.9.1\mingw_64\bin\windeployqt --release xxxxxx.exe)打包。
其他:
添加图标:使用转换工具把图片转换为.ico文件,然后放在QT工程目录下,QT中使用qmake编译的话直接在.pro添加文件中添加RC_ICONS = logo.ico即可。
差分包制作
差分包制作工具位于components/ota/diff_upgrade/diff_upgrade_lzma.exe,相关脚本基于python2.7。
安装python2.7
安装pycryptodome算法库
GitHub
pip install --upgrade pip //更新pip
pip install pycryptodome==3.7.2
- python2在2.7.9及之后的版本支持pip,如果安装的python版本比较低,可以先升级pip。
- pycryptodome安装时最好指定版本,不要下载最新的。
如果下载了pycryptodome库,源码目录下,使用setup.py进行安装。
python setup.py install
差分包制作
diff_upgrade_lzma.exe [-o old_bin_file] [-n new_bin_file] [-p patch_bin_file] [-max_image xxxx] [-max_patch xxxx] [-block_size xxxx] [-erase_size xxxx]
old_bin_file:旧的Bin文件。
new_bin_file:新的Bin文件。
patch_bin_file:生成的差分包。
max_image:最大镜像区大小,最大不超过8MB。
max_patch:最大差分包大小。
block_size:分块还原单位。算法以分块为单位进行还原,一次输出 1 个块大小的还原数据。该字段大小必须是 erase_size 的整数倍。
erase_size:MCU 侧 Flash 最小擦除单位。
以本次实现为例,同时支持差分和全量升级,所以差分包和镜像区的大小设置的一样:
C:\Python27\ota\diff_upgrade_lzma.exe -o E:\SourceBin\V1.0.bin -n E:\SourceBin\V1.1.bin -p patch.bin -max_image 51200 -max_patch 51200 -block_size 4096 -erase_size 2048
升级包制作
1.修改配置文件config.xml,只需要修改校验方式和升级方式。
2.制作升级包
package_software.py [-c config_xml_file] [-o output_file] -i input_file
config_xml_file:升级包配置文件。
output_file:最终输出的升级包。
input_file:待打包文件。
以本次实现为例:
//差分升级
C:\Python27\ota\package_software.py -c C:\Python27\ota\config_diff.xml -o V1.0_To_V1.1.bin -i C:\Python27\Scripts\patch.bin
//全量升级
C:\Python27\ota\package_software.py -c C:\Python27\ota\config_full.xml -o V1.0_To_V1.2.bin -i E:\SourceBin\V1.2.bin
如果是全量升级,不需要制作差分包,直接第二步中制作升级包就可以。升级包与差分包的区别是制作好的升级包相较于差分包头部增加20字节数据,用于指示升级类型等关键信息;这些信息在App中获取升级包时会解析,并存储关键信息到Sota Flag中。Image Download区域存储的实际上就是差分包。
设备端具体实现
App程序负责接收版本推送和下载镜像,Boot中完成还原场景,并编译固件到App区域。根据需要可以实现固件的更新和回滚。
工程目录结构
MCU使用STM32L433。
Flash相关
App与Boot使用相同的Flash读写函数
static uint32_t GetPage(uint32_t Addr)
{uint32_t page = 0;if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)){/* Bank 1 */page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;}else{/* Bank 2 */page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;}return page;
}FlashProcStatus_e device_flash_write(uint8_t *buf, uint32_t len, uint32_t start_addr)
{uint32_t PageError = 0,i = 0,end_addr = 0,write_addr = 0;FLASH_EraseInitTypeDef EraseInitStruct;if((buf == NULL) || (len <= 0) || (len > OTA_DEFAULT_IMAGE_SIZE)){return FLASH_PROC_ERROR;}end_addr = start_addr + len;if((end_addr > FLASH_END_ADDR) || (start_addr % 4 != 0)){return FLASH_PROC_ERROR;}__disable_irq();HAL_FLASH_Unlock();__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);for