MS-RTOS OTA 升级
本章将介绍 MS-RTOS OTA 升级服务的实现。
OTA 升级流程
OTA 升级服务是一个 APP 或内核服务,它负责与远程的升级服务器通信,当有新固件发布时,它主动下载的新版本 OS 镜像、APP 镜像、启动参数文件(这些文件可以是差分文件,也允许只升级部分文件)到外部文件系统,在外部文件系统中生成升级动作文件和升级请求文件,然后调用 ms_rtos_update
函数,MS-RTOS 将文件系统 CACHE 回写到磁盘后进行重启。重启后由 MS-BOOT 进行 OS 镜像的升级工作,由 MS-RTOS 进行 APP 镜像、启动参数文件的升级工作。
OTA 升级服务
流程:
- 下载新版本 OS 镜像、APP 镜像、启动参数文件到外部文件系统
- 如果是差分包,利用
ms_patch
函数生成新的完整包 - 检查固件的完整性、合法性
- 在外部文件系统中创建升级动作文件
- 在外部文件系统中创建升级请求文件
- 调用
ms_rtos_update
函数
新固件下载
下载的新版本 OS 镜像、APP 镜像、启动参数文件到外部文件系统。下载完毕后需要检查固件的完整性、合法性。
创建升级请求文件
升级请求文件是系统重启时 MS-BOOT 和 MS-RTOS 用来判断是否需要升级的标志。
升级请求文件储存了升级动作文件的路径。
在 OTA 升级服务程序中可以使用如下代码创建升级请求文件:
#define __UPDATE_ACTIONS_PATH "/nor/update/update_actions"
#define __UPDATE_REQUEST_PATH "/nor/update/update_req"
fd = ms_io_creat(__UPDATE_REQUEST_PATH, 0666);
ms_io_write(fd, __UPDATE_ACTIONS_PATH, sizeof(__UPDATE_ACTIONS_PATH));
ms_io_close(fd);
创建升级动作文件
升级动作文件描述了升级过程需要执行哪些动作。
升级动作文件内容是一个 ms_flashfs_action_t
类型的数组,每个元素是一个升级动作:
MS_STRUCT_PACK_BEGIN
struct ms_flashfs_action {
// 动作 id
#define MS_FLASHFS_ACTION_CREATE_FILE 0U // 创建文件
#define MS_FLASHFS_ACTION_UPDATE_FILE 1U // 升级文件
#define MS_FLASHFS_ACTION_REMOVE_FILE 2U // 删除文件
#define MS_FLASHFS_ACTION_DEFRAG 3U // 磁盘碎片整理
#define MS_FLASHFS_ACTION_UPDATE_OS 4U // 升级 OS 镜像(该类型动作由 MS-BOOT 执行)
MS_STRUCT_PACK_FIELD(ms_uint32_t id); // 动作 id
MS_STRUCT_PACK_FIELD(ms_uint32_t reserve_size); // 预留给未来升级的大小
MS_STRUCT_PACK_FIELD(ms_uint32_t crc32); // 文件的 CRC32
MS_STRUCT_PACK_FIELD(ms_err_t err); // 动作执行的错误码
MS_STRUCT_PACK_FIELD(char name[MS_FLASHFS_NAME_BUF_SIZE]); // 文件名
MS_STRUCT_PACK_FIELD(char source[MS_FLASHFS_PATH_BUF_SIZE]); // 外部文件系统中的源文件
} MS_STRUCT_PACK_STRUCT;
MS_STRUCT_PACK_END
typedef struct ms_flashfs_action ms_flashfs_action_t;
在 OTA 升级服务程序中可以使用如下代码创建升级动作文件:
#define __UPDATE_FIRMWARE_PATH(x) "/nor/update/firmware/"x
#define __UPDATE_ACTIONS_PATH "/nor/update/update_actions"
#define __UPDATE_REQUEST_PATH "/nor/update/update_req"
ms_flashfs_action_t actions[2];
/*
* 创建启动参数文件 ms-boot-param.dtb 动作
*/
actions[0].id = MS_FLASHFS_ACTION_CREATE_FILE;
actions[0].reserve_size = 0;
actions[0].err = MS_ERR_NONE;
ms_file_crc32(__UPDATE_FIRMWARE_PATH("ms-boot-param.dtb"), &actions[0].crc32);
strcpy(actions[0].name, "ms-boot-param.dtb");
strcpy(actions[0].source, __UPDATE_FIRMWARE_PATH("ms-boot-param.dtb"));
/*
* 安装应用 app1.bin 动作
*/
actions[1].id = MS_FLASHFS_ACTION_CREATE_FILE;
actions[1].reserve_size = 0;
actions[1].err = MS_ERR_NONE;
ms_file_crc32(__UPDATE_FIRMWARE_PATH("app1.bin"), &actions[1].crc32);
strcpy(actions[1].name, "app1.bin");
strcpy(actions[1].source, __UPDATE_FIRMWARE_PATH("app1.bin"));
/* 其它动作 */
/*
* 创建升级动作文件
*/
int fd = ms_io_creat(__UPDATE_ACTIONS_PATH, 0666);
ms_io_write(fd, actions, sizeof(actions));
ms_io_close(fd);
BOOTLOADER 要求
CPU 重启后,首先运行 BOOTLOADER,OS 镜像的升级需要由 BOOTLOADER 完成,以下是 BOOTLOADER 的升级流程:
- 判断升级请求文件是否存在,如果不存在,则启动 MS-RTOS
- 从升级请求文件读出升级动作文件的路径
- 判断升级动作文件是否存在,如果不存在,则启动 MS-RTOS,如果存在,则加载升级动作文件到内存
- 分析所有升级动作,如果有升级 OS 的动作(
id
为MS_FLASHFS_ACTION_UPDATE_OS
),则升级 MS-RTOS 镜像 - 启动 MS-RTOS
BSP 要求
APP 镜像、启动参数文件的升级由 MS-RTOS 完成。MS-RTOS 重启后,在 BSP 中,一般由启动线程 boot_thread
来调用 ms_apps_update
函数。
ms_err_t ms_apps_update(const char *update_req_path, const char *log_path);
static void boot_thread(ms_ptr_t arg)
{
// do something
ms_launcher_init(rsa_pub_key, rsa_pub_key_len);
ms_apps_update("/nor/update/firmware/update_req", "/nor/update/firmware/update_log");
// do something
}
ms_apps_update
函数按顺序执行升级动作文件中的每个动作,执行的出错时会将错误码写到升级动作文件,并将升级日志记录到指定的日志文件中。
差分升级
MS-RTOS 提供了差分升级的支持,可有效节约升级通信时间和流量,实现快速升级。
相关 API
// 使用旧的文件和差分包生成新的文件
int ms_patch(const char *old_file, const char *new_file, const char *patch_file);
如果要使用差分函数 ms_patch
,应用程序需要链接 libmspatch.a
静态库,即 xxx.mk
的 LOCAL_DEPEND_LIB
需要添加 -lmspatch
。BSP 需要链接 libmskpatch.a
静态库,即 bspxxx.mk
的 LOCAL_DEPEND_LIB
需要添加 -lmskpatch
。
生成差分包
差分包生成工具比较旧文件和新文件的差异性,生成较小的补丁文件:
msrtos-diff oldfile newfile patchfile