固件升级与更新机制
AC792N SDK 的固件升级子系统是一套支持多传输通道(RCSP/APP、HTTP、网络)、多存储介质(NOR Flash、UFW 分区、扩展区)、带 CRC 校验与备份回滚的完整 OTA 更新框架。本文档从入口、核心流程、存储布局、校验算法到失败处理,系统性地解析该机制的实现。
Purpose and Scope
本页覆盖 AC792N SDK 中与"固件升级与更新"相关的完整能力:
- 升级子系统的文件构成与分层(
sdk/apps/common/update/目录) - NOR Flash 升级通路(
norflash_update.c)的逐行实现剖析:loader 下载、写入、CRC16 回读校验 - RCSP 升级通道(APP 通过蓝牙/串口下发升级包)与 TWS 双设备升级
- 网络升级(
http_update.c、net_update.c)与单备份升级(net_single_backup_update.c) - 压缩升级(
compress_update)与扩展区文件更新(expand_zone_file_update.c、ex_flash_file_download.c)
不在本页范围:RCSP 协议本身的帧格式与蓝牙连接管理(属于蓝牙协议栈/Profile 范畴)、文件系统 nor_fs 的底层实现、网络协议栈细节。这些能力各有独立页面,本文仅在必要时引用其入口。
Overview
固件升级是嵌入式音频/IoT 设备(AC792N 芯片)生命周期管理中最关键的一环:设备出厂后需要在线修复缺陷、更新算法参数或增加功能。AC792N SDK 的升级机制采用**"下载即校验、校验即生效、失败可回退"**的设计原则:
- 多通道接入:升级请求既可以来自本地调试(loader 文件直接写入),也可以来自 APP 通过 RCSP 协议(蓝牙)、或通过 HTTP/网络远程拉取固件包。
- 分阶段落盘:升级包不直接覆盖运行区,而是先写入独立的升级区域(如
storage/nor_fs/C/loader.bin),全部写完后统一回读校验,校验通过才触发切换。 - CRC 完整性保证:写入完成后用
CRC16_with_initval全量回读计算,与下发方提供的loader_crc比对,任何一位错误都会导致升级被拒绝,从而避免半砖设备。 - 备份与回滚:
net_single_backup_update.c等模块在升级前保留运行固件副本,升级失败时可恢复旧版本。
这套机制的核心价值在于:把"不可靠的无线传输"与"不可中断的固件运行区"解耦——传输可以断点重来、校验失败可以丢弃重下,而运行区只有在全部数据完整时才被切换,最大程度降低升级导致的设备变砖风险。
Architecture
flowchart TD
subgraph sg_Channel["升级入口 / 传输通道"]
RCSP["rcsp_update.c<br/>RCSP APP 升级(服务器)"]
RCSP_TWS["rcsp_update_tws.c<br/>TWS 双设备升级"]
RCSP_M["rcsp_update_master.c<br/>RCSP 升级客户端"]
HTTP["http_update.c<br/>HTTP 下载升级"]
NET["net_update.c<br/>网络升级"]
end
subgraph sg_Core["升级核心 / 调度与校验"]
FS_UPDATE["fs_update.c<br/>文件系统更新"]
UFW["norflash_ufw_update.c<br/>UFW 固件格式更新"]
SINGLE_BACKUP["net_single_backup_update.c<br/>单备份升级"]
EXPAND["expand_zone_file_update.c<br/>扩展区文件更新"]
end
subgraph sg_Storage["存储 / 落盘层"]
NOR["norflash_update.c<br/>NOR Flash loader 写入与 CRC 校验"]
EXFLASH["ex_flash_file_download.c<br/>外挂 Flash 下载"]
NORFS[("nor_fs 文件系统<br/>storage/nor_fs/C/loader.bin")]
UFW_ZONE[("UFW 固件分区")]
end
RCSP --> FS_UPDATE
RCSP --> UFW
RCSP_TWS --> UFW
RCSP_M --> UFW
HTTP --> NET
NET --> SINGLE_BACKUP
SINGLE_BACKUP --> NOR
FS_UPDATE --> NOR
UFW --> NOR
EXPAND --> EXFLASH
NOR --> NORFS
UFW --> UFW_ZONE
架构解读:整个升级子系统呈"入口 → 核心 → 存储"三层结构。上层是各类传输通道(RCSP 是杰理私有协议,用于 APP 通过蓝牙/串口与设备交互;HTTP/网络用于远程 OTA);中层是升级策略实现,负责将下载的数据按目标格式(UFW 通用固件格式、文件系统更新、扩展区更新)组织;底层 norflash_update.c 是所有 NOR Flash 介质升级的公共落盘与校验单元——它把升级包以普通文件的方式写入 nor_fs 文件系统的 loader.bin,再用 CRC16 回读校验,是整套机制的"最后一道保险"。
升级子系统文件构成
固件升级相关代码集中分布在两个位置:sdk/apps/common/update/(通用更新核心)与 sdk/apps/common/third_party_profile/jieli/rcsp/(RCSP 协议升级通道)。官方文档入口位于 cache/V1.0.0/docs/html/_sources/SDK/system/通用组件/update/,其 index.rst.txt 通过 toctree 挂载了 compress_update.rst(压缩升级)章节。
| 文件 | 角色 | 归属层 |
|---|---|---|
update/norflash_update.c | NOR Flash loader 写入 + CRC16 回读校验 | 存储层(核心) |
update/norflash_ufw_update.c | UFW 通用固件格式升级 | 升级核心 |
update/fs_update.c | 基于文件系统的固件更新调度 | 升级核心 |
update/http_update.c | HTTP 通道下载固件包 | 入口/传输 |
update/net_update.c | 通用网络升级入口 | 入口/传输 |
update/net_single_backup_update.c | 单备份(升级前保留旧固件)升级策略 | 升级核心 |
update/expand_zone_file_update.c | 扩展区文件更新(参数/资源区) | 升级核心 |
update/ex_flash_file_download.c | 外挂 Flash 文件下载 | 存储层 |
rcsp/server/functions/rcsp_update/rcsp_update.c/.h | RCSP 升级服务器(APP 主控侧服务) | 入口/传输 |
rcsp/server/functions/rcsp_update/rcsp_update_tws.c/.h | TWS 双耳联动升级 | 入口/传输 |
rcsp/server/functions/rcsp_update/rcsp_ch_loader_download.c/.h | RCSP loader 下载专用通道 | 入口/传输 |
rcsp/client/rcsp_m_update/rcsp_update_master.c/.h | RCSP 升级客户端(设备作为主控) | 入口/传输 |
说明:本表基于目录清单与文件名推断各模块职责;除
norflash_update.c已逐行核实外,其余模块的职责描述来自命名与 RCSP 框架约定,细节以各文件源码为准。
NOR Flash 升级通路(norflash_update.c)逐行剖析
norflash_update.c 是整个升级机制中与硬件最近的公共单元。它没有直接操作 flash 寄存器,而是复用 nor_fs 文件系统:把升级包(loader)当做一个普通文件写入,之后回读该文件计算 CRC16,与下发方携带的校验值比对。这种"文件化落盘 + 回读校验"的设计让上层通道(RCSP/网络/本地)完全不需要关心 flash 的擦写细节。
1. 升级区域参数结构
typedef struct _nor_fs_part {
u32 update_file_addr;
u32 update_area_start_addr;
u32 update_area_end_addr;
} nor_fs_parm;
nor_fs_parm update_norfs_parm;
Source: norflash_update.c
该结构记录升级文件在 flash 中的绝对地址(update_file_addr)以及整个升级区域的起始/结束地址。它由全局变量 update_norfs_parm 持有,供上层通过 get_nor_update_param() 查询——设计意图是让上层(如 bootloader 或 RCSP 服务)在复位切换前能够拿到升级包的物理位置,从而决定从哪个地址启动新固件。
2. 打开升级文件(norflash_f_open)
#define NORFLASH_LOADER_PATH "storage/nor_fs/C/loader.bin"
int norflash_f_open(u32 loader_len)
{
fd = fopen(NORFLASH_LOADER_PATH, "w+");
if (!fd) {
r_printf("update fopen err\n");
return -1;
} else {
g_printf("update fopen succ\n");
update_norfs_parm.update_file_addr = nor_get_absolute_addr();
update_norfs_parm.update_area_start_addr = nor_get_start_addr();
update_norfs_parm.update_area_end_addr = update_norfs_parm.update_area_start_addr + nor_get_capacity();
if (loader_len > nor_get_capacity) {
return -2;
}
}
return 0;
}
Source: norflash_update.c
要点:
- 升级包固定写入
storage/nor_fs/C/loader.bin,"w+"模式表示可写可读,为后续回读校验做准备。 - 文件打开成功后,通过
nor_get_absolute_addr()/nor_get_start_addr()/nor_get_capacity()三个查询函数填充升级区域参数。这三个函数由底层 norflash 驱动提供(本文件仅声明),实际返回的是当前 loader 存储分区的物理布局。 - 边界检查
loader_len > nor_get_capacity存在一个明显的笔误:nor_get_capacity是函数地址而非调用(应为nor_get_capacity()),因此该判断实际是"loader 长度大于函数地址则失败"。这是源码中可留意的缺陷,生产代码通常不会触发,但审计时应修正为函数调用。 - 失败码约定:
-1表示打开文件失败(如文件系统未挂载、空间不足),-2表示升级包超过升级区容量。
3. 写入回调(norflash_f_write)
static u16 norflash_f_write(void *buff, u32 addr, u32 len)
{
if (fd) {
return fwrite(fd, buff, len);
}
return 0;
}
Source: norflash_update.c
norflash_f_write 通过 register_loader_write_handler() 注册为 loader 写入回调。上层(如 RCSP 的 rcsp_ch_loader_download 或 UFW 升级流程)只调用统一的写处理器接口,无需感知底层是 nor_fs 文件系统还是裸 flash——这是典型的回调解耦设计:norflash_loader_start() 把静态写函数挂到全局处理器上,升级数据流便与具体存储实现解耦。注意 addr 参数在此实现中被忽略,因为文件系统内部自己维护写位置。
4. CRC16 回读校验(norflash_update_verify)
u32 norflash_update_verify(u32 loader_len, u32 loader_crc)
{
u32 len = loader_len;
u32 crc_temp = 0;
if (fd) {
fseek(fd, NOR_FS_SEEK_SET, 0); //偏移到文件起始
u16 r_len;
u8 *temp_buf = malloc(512);
if (NULL == temp_buf) {
goto _ERR_RET;
}
u16 temp_buf_len = 512;
while (len) {
r_len = (len > temp_buf_len) ? temp_buf_len : len;
fread(fd, temp_buf, r_len);
crc_temp = CRC16_with_initval(temp_buf, r_len, crc_temp);
len -= r_len;
}
_ERR_RET:
if (NULL != temp_buf) {
free(temp_buf);
}
if (crc_temp == loader_crc) {
return 0;
}
}
return 1;
}
Source: norflash_update.c
这是升级安全的核心校验函数,设计意图值得细读:
fseek(fd, NOR_FS_SEEK_SET, 0)把文件指针归零,从文件头开始回读——校验的是"实际写入 flash 的字节",而非内存中缓存的字节,能捕获写中断、坏块、部分擦除等真实存储错误。- 以 512 字节为块循环
fread+CRC16_with_initval累积计算 CRC。crc_temp作为初始值传入下一轮,实现跨块的链式 CRC——这与传输层分片下发、接收端边收边算的校验方式保持一致,双方使用同一初始值(通常为 0 或 0xFFFF)即可对齐。 - 内存不足时跳转到
_ERR_RET,此时crc_temp仍为 0,与loader_crc相等才会误判通过;因此实际上下层保证loader_crc非 0,或该路径因返回 1(校验失败)被上层拒绝。这是一个理论上存在、实践中依赖上层约束的边界。 - 返回值约定:
0= 校验通过,1= 校验失败或文件句柄无效。上层只有在收到0时才允许提交升级(复位/切换分区)。
5. 收尾与启动入口
void norflash_update_close()
{
if (fd) {
fclose(fd);
}
}
int norflash_loader_start(u32 loader_len)
{
register_loader_write_handler(norflash_f_write);
return norflash_f_open(loader_len);
}
Source: norflash_update.c
norflash_loader_start()是升级流程的标准入口:先注册写回调,再打开升级文件。返回 0 表示就绪,负值表示失败(见上文失败码)。norflash_update_close()负责释放文件句柄,必须在校验通过、提交升级前调用,否则nor_fs缓存可能未落盘。
6. 参数查询(get_nor_update_param)
int get_nor_update_param(void *buf)
{
if (buf) {
printf("file_addr:0x%x start_addr:0x%x end_addr:0x%x\n", update_norfs_parm.update_file_addr, update_norfs_parm.update_area_start_addr, update_norfs_parm.update_area_end_addr);
memcpy(buf, (u8 *)&update_norfs_parm, sizeof(update_norfs_parm));
}
return sizeof(update_norfs_parm);
}
Source: norflash_update.c
该函数把升级区域的物理布局暴露给调用方(典型调用方是 bootloader 切换逻辑或调试工具),返回结构体字节数;buf 为 NULL 时仅返回长度,可用来先查询大小再分配缓冲区。
RCSP 升级通道(APP 蓝牙升级)
RCSP(杰理私有远程控制/服务协议)升级是消费类音频产品(耳机、音箱)最主要的升级方式:手机 APP 通过蓝牙把固件分包下发到设备。相关实现位于 sdk/apps/common/third_party_profile/jieli/rcsp/,按角色分为三组:
- 服务器侧(设备作为被控端):
rcsp/server/functions/rcsp_update/rcsp_update.c处理 APP 的升级请求、版本协商、数据分片接收与写入调度;rcsp_ch_loader_download.c是专门的 loader 下载通道,负责把 APP 下发的 loader 数据交给norflash_loader_start()注册的写回调;rcsp_update_tws.c处理 TWS 双耳场景——主耳收到升级包后需要同步转发给副耳,保证两只耳机固件版本一致。 - 客户端侧(设备作为主控去升级从设备):
rcsp/client/rcsp_m_update/rcsp_update_master.c用于设备主动向对端(如充电盒、另一只耳机)发起升级,是服务器侧的镜像角色。
RCSP 升级与底层 norflash_update.c 的衔接正是通过 register_loader_write_handler() 完成:RCSP 数据帧解析出 loader 字节流后,直接调用写处理器落盘,全程不感知 flash 细节;收包完成后调用 norflash_update_verify() 做整体 CRC 校验,再触发复位切换。
网络/HTTP 升级通道
flowchart LR
subgraph sg_Net["网络升级路径"]
HTTP["http_update.c"] --> NET["net_update.c"]
NET --> SINGLE["net_single_backup_update.c<br/>单备份策略"]
SINGLE --> NOR["norflash_update.c<br/>落盘 + CRC"]
end
http_update.c:通过 HTTP 协议从服务器拉取固件包,适用于有 Wi-Fi 能力的设备(如本 SDK 中的 wifi_camera 应用)。负责建立连接、按块下载、断点续传等传输层工作。net_update.c:网络升级的统一入口,封装下载完成后到写入/校验的衔接。net_single_backup_update.c:实现"单备份"升级策略——升级前把当前运行固件备份到保留区,新固件写入后若校验失败或启动异常,可回滚到备份版本。该策略是无线 OTA 场景下降低变砖概率的关键设计。
压缩升级(compress_update)
官方文档目录 cache/V1.0.0/docs/html/_sources/SDK/system/通用组件/update/ 下的 index.rst.txt 通过 toctree 挂载了 compress_update.rst 章节,说明 SDK 支持压缩升级:固件包先压缩再传输,设备端解压后写入。压缩升级的价值在于显著减少无线传输时间与电量消耗——对蓝牙 BLE 这种低吞吐、短连接窗口的通道尤为重要。具体压缩算法与解压流程详见该文档章节:compress_update.rst。
Core Flow:一次完整升级的生命周期
以下时序图描述"APP 通过 RCSP 发起、设备经 NOR Flash 通路落盘"的典型升级流程(网络/HTTP 路径的差异仅在传输层):
sequenceDiagram
participant APP as 手机APP (RCSP)
participant RCSP as rcsp_update.c
participant LOADER as rcsp_ch_loader_download.c
participant NOR as norflash_update.c
participant FS as nor_fs (loader.bin)
APP->>RCSP: 升级请求(固件版本/长度/CRC)
RCSP->>RCSP: 版本协商与合法性检查
RCSP->>NOR: norflash_loader_start(loader_len)
NOR->>NOR: register_loader_write_handler(norflash_f_write)
NOR->>FS: fopen("storage/nor_fs/C/loader.bin","w+")
FS-->>NOR: fd 就绪(0) / 失败(-1,-2)
RCSP->>LOADER: 进入 loader 下载通道
loop 分片下发
APP->>LOADER: 数据分片(含片内CRC)
LOADER->>NOR: norflash_f_write(buff, addr, len)
NOR->>FS: fwrite(fd, buff, len)
end
APP->>RCSP: 下载完成 + loader_crc
RCSP->>NOR: norflash_update_verify(loader_len, loader_crc)
NOR->>FS: fseek 归零 + 512B分块回读
NOR->>NOR: CRC16_with_initval 链式累积
FS-->>NOR: 回读字节流
NOR-->>RCSP: 0(通过) / 1(失败)
alt 校验通过
RCSP->>NOR: norflash_update_close()
RCSP->>RCSP: 复位/切换启动新固件
else 校验失败
RCSP->>RCSP: 丢弃升级包, 保持旧固件运行
end
流程要点:
- 先协商后下载:升级不是"拿到就写",而是先做版本协商,避免重复刷写相同版本、防止降级(是否允许降级由上层策略决定)。
- 写回调提前注册:
norflash_loader_start()在打开文件前先注册写处理器,保证任何分片数据到达时写入路径已就绪。 - 边收边写、整体校验:传输过程中不做全局校验(避免内存缓冲整包),全部落盘后一次性回读校验。这一设计把内存占用压到 512 字节级,代价是坏块只能在收包完成后被发现——因此上层必须支持"校验失败后重新发起升级"。
- 失败零成本回退:校验失败时设备仍运行旧固件,只是丢弃新包,不产生任何副作用;这是整套机制安全性的基石。
API Reference
以下 API 均来自 sdk/apps/common/update/norflash_update.c,是 NOR Flash 升级通路的公共接口(源码出处见各节签名后的链接)。
int norflash_loader_start(u32 loader_len)
升级流程标准入口:注册写回调并打开升级文件。
- 参数:
loader_len— 待写入 loader 的长度(字节)。 - 返回:
0成功;-1打开storage/nor_fs/C/loader.bin失败(文件系统未就绪/空间不足);-2loader 长度超出升级区容量(受源码中loader_len > nor_get_capacity笔误影响,该分支实际很少触发)。
Source: norflash_update.c
int norflash_f_open(u32 loader_len)
打开升级文件并初始化升级区域参数。
- 参数:
loader_len— 待写入 loader 的长度(字节)。 - 返回:
0成功;-1fopen失败;-2长度超容量。 - 副作用:填充全局
update_norfs_parm(update_file_addr、update_area_start_addr、update_area_end_addr)。
Source: norflash_update.c
static u16 norflash_f_write(void *buff, u32 addr, u32 len)
loader 写入回调(经 register_loader_write_handler 注册)。
- 参数:
buff数据指针;addr目标地址(当前实现忽略,由文件系统维护写位置);len写入长度。 - 返回:实际写入字节数;文件句柄无效时返回
0。
Source: norflash_update.c
u32 norflash_update_verify(u32 loader_len, u32 loader_crc)
回读升级文件并链式计算 CRC16,与下发方校验值比对。
- 参数:
loader_len总长度;loader_crc期望 CRC 值。 - 返回:
0校验通过;1校验失败(含文件句柄无效、内存分配失败路径)。 - 实现:512 字节分块
fread+CRC16_with_initval累积;内存不足时goto _ERR_RET,此时crc_temp为 0,依赖上层保证loader_crc != 0避免误判。
Source: norflash_update.c
void norflash_update_close()
关闭升级文件句柄,必须在提交升级(复位切换)前调用以确保缓存落盘。
Source: norflash_update.c
int get_nor_update_param(void *buf)
导出升级区域物理布局参数。
- 参数:
buf输出缓冲区(nor_fs_parm结构,16 字节);可为 NULL。 - 返回:
sizeof(nor_fs_parm)。
Source: norflash_update.c
void register_loader_write_handler(u32(*hdl)(const void *, u32, u32))
注册 loader 写入回调(由底层驱动/其他模块实现),norflash_loader_start 内部调用,也是 RCSP 等上层通道与存储层解耦的钩子。
Source: norflash_update.c
Configuration Options
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
NORFLASH_LOADER_PATH | 宏(路径字符串) | "storage/nor_fs/C/loader.bin" | loader 升级包在 nor_fs 中的落盘路径;"w+" 模式打开,支持写入后回读校验 |
update_norfs_parm.update_file_addr | u32 | 由 nor_get_absolute_addr() 填充 | 升级文件在 flash 中的绝对地址 |
update_norfs_parm.update_area_start_addr | u32 | 由 nor_get_start_addr() 填充 | 升级区域起始地址 |
update_norfs_parm.update_area_end_addr | u32 | start + nor_get_capacity() | 升级区域结束地址(= 起始 + 容量) |
| CRC 分块大小 | 常量(局部) | 512 字节 | 回读校验时的临时缓冲区大小,即每次 fread/CRC 累积的块长 |
Source: norflash_update.c
Failure Modes, Edge Cases & Concurrency
已核实的失败路径
| 失败场景 | 表现 | 处理 |
|---|---|---|
fopen 失败(文件系统未挂载/空间不足) | norflash_f_open 返回 -1,打印 update fopen err | 上层应终止升级流程并保持旧固件 |
| loader 长度超容量 | 返回 -2 | 终止升级;注意该判断在源码中因笔误(nor_get_capacity 未加括号)实际几乎不生效 |
| CRC 校验失败 | norflash_update_verify 返回 1 | 丢弃升级包,设备继续运行旧固件,等待重试 |
| 回读时内存分配失败 | malloc(512) 返回 NULL,跳 _ERR_RET | crc_temp 保持 0,若 loader_crc 恰为 0 会误判通过——上层应保证下发 CRC 非 0 |
| 文件句柄无效时写入 | norflash_f_write 返回 0 | 上层应检测写入字节数不足并中止 |
边界与一致性
- 写地址语义:
norflash_f_write忽略addr参数,位置由nor_fs文件系统内部维护;调用方若依赖绝对地址写入(如裸 flash 直写场景)需使用其他通路(norflash_ufw_update.c等)。 - 校验与切换的原子性:CRC 通过后立即
close+ 复位,切换期间不可被打断;get_nor_update_param供 bootloader 在复位后定位新固件入口。 - 并发模型:本模块通过全局
fd与全局update_norfs_parm工作,不支持多线程/多任务并发升级。升级期间应保证只有一个写者(RCSP 或网络通道二选一),且写回调注册是覆盖式(后注册者生效)。TWS 场景下主/副耳的升级由rcsp_update_tws.c串行编排,避免双通道竞争同一fd。
传输层与存储层的一致性保证
设计上,"边收边写 + 整体回读校验"意味着传输层的分片 CRC 只保证单包无错,全量正确性由最终的 norflash_update_verify 兜底。因此任何"最后一包已确认"都不能作为升级成功的依据——必须以 norflash_update_verify == 0 为唯一成功判据。
Performance & Operational Notes
- 内存占用极低:CRC 回读校验仅需 512 字节临时缓冲区,加上文件句柄与参数结构,整个 NOR 升级通路的 RAM 开销不超过 1KB——这对音频设备紧张的 RAM 预算至关重要,也是选择"边收边写、整体校验"而非"整包缓冲"的根本原因。
- I/O 模式:写入为流式
fwrite,校验为 512 字节分块顺序fread。顺序读写对nor_fs友好,但每块一次文件系统调用;若升级包达数百 KB,校验阶段会成为 CPU/I/O 热点,可考虑增大分块(如 4KB)换取吞吐,代价是 RAM 占用上升。 - CRC 计算成本:
CRC16_with_initval为逐字节查表/移位实现,属轻量计算;但对大固件包全量计算仍需毫秒级时间,建议在校验期间关闭不必要的定时任务或延长看门狗,防止校验被误判为死机。 - 运维建议:OTA 服务器应随包下发
loader_crc(与设备端CRC16_with_initval使用相同初始值),并支持断点重传;设备端日志(update fopen succ/update fopen err)可作为升级失败的快速定位线索。 - 升级区容量规划:
update_area_end_addr = start + nor_get_capacity(),bootloader 的启动地址选择必须与get_nor_update_param()返回的布局一致,否则校验通过后可能从错误地址启动。
Extension Points
升级子系统为二次开发预留了明确的扩展接口:
register_loader_write_handler— 核心扩展点。默认实现把数据写入nor_fs的loader.bin;如需改为裸 flash 直写、加密存储或外挂 Flash(参考ex_flash_file_download.c),只需注册自定义写回调,上层 RCSP/网络通道无需改动。norflash_update_verify的 CRC 算法替换 — 若产品需要更健壮的完整性校验(如 CRC32/SHA),可在保持loader_crc参数语义的前提下替换实现;注意须与下发方算法对齐。- 新增传输通道 — 参照
http_update.c/rcsp_ch_loader_download.c的模式,新通道只需完成"接收数据 → 调norflash_loader_start→ 循环调写回调 → 调norflash_update_verify"四步即可接入既有校验与切换框架。 - 升级策略 —
net_single_backup_update.c展示了备份回滚策略;产品若需双备份(A/B 分区)或多副本,可在升级核心层新增策略模块,复用本页描述的落盘与校验原语。
Tests
本次源码探索未在 sdk/apps/common/update/ 及相关 RCSP 目录中发现对应的单元测试或自动化测试文件(该 SDK 为嵌入式工程,测试通常依赖硬件台架与 nor_fs 的坏块模拟)。验证手段主要为:
- 功能验证:通过 RCSP/APP 或网络通道完成一次完整升级,确认
norflash_update_verify返回0且设备复位后运行新固件。 - 故障注入:传输中断、篡改分片数据后确认校验返回
1且设备仍能正常启动旧固件。 - 边界验证:
loader_len超容量、文件系统未就绪时调用norflash_loader_start的返回值是否符合-1/-2约定。
说明:以上验证建议基于接口契约推导,并非仓库内现成测试用例;如仓库后续补充测试,请以实际文件为准。
Related Links
- 官方文档(升级组件索引):update/index.rst.txt
- 压缩升级说明:compress_update.rst.txt
- 核心实现(NOR Flash 升级通路):norflash_update.c
- 关联升级模块(同目录):norflash_ufw_update.c | fs_update.c | http_update.c | net_update.c | net_single_backup_update.c | expand_zone_file_update.c | ex_flash_file_download.c
- RCSP 升级服务端:rcsp_update.c | rcsp_update_tws.c | rcsp_ch_loader_download.c
- RCSP 升级客户端:rcsp_update_master.c
本文档基于仓库 release/AC792N_SDK_V3 分支源码编写。核心 API 与代码片段均出自 norflash_update.c 实际源码;其余模块的职责描述来自目录清单与文件命名推断,已在上文明确标注,深入使用前请以各文件源码为准。