跳转至

FOTA 开发指南

本文档介绍 HiDiTingV100 的 FOTA(Firmware Over-The-Air,固件空中升级)能力,并以 diting-community 应用镜像升级为例,说明升级包制作、传输、校验、升级和结果确认的完整流程。

本文档还介绍 FOTA 模块的工作原理、关键配置和验证方法,帮助开发者基于 SDK 提供的接口构建产品升级业务。


FOTA 背景知识

FOTA 工作原理

FOTA 用于在不重新烧录整机固件的情况下更新设备软件。升级系统通常由升级包制作端、升级包传输端和目标设备三部分组成:

组成部分 主要职责 HiDiTingV100 对应实现
升级包制作端 选择新旧镜像,完成签名、压缩或差分处理,生成升级包 build_3322_update.pyfota.cfgbuild_upg_pkg.py
升级包传输端 update.fwpkg 传输到设备 DebugKits、产品自定义网络或有线传输模块
目标设备 保存升级包、校验合法性、设置升级标记、更新镜像并记录结果 Upgrade UAPI、文件系统、Recovery

HiDiTingV100 支持以下升级模式:

升级模式 配置值 说明 适用场景
全量升级 DecompressFlag=0 将完整的新镜像写入目标分区 初次集成、镜像变化较大或需要简化升级包制作流程
压缩升级 DecompressFlag=0x3C7896E1 传输压缩后的新镜像,设备侧解压后更新 希望减少升级包体积,设备存储和耗时允许
差分升级 DecompressFlag=0x44494646 根据旧镜像与新镜像生成差分数据,设备侧还原新镜像 版本演进路径明确、需要进一步减小升级包

注意事项:

  • NV 镜像仅支持全量升级。
  • 资源文件支持全量升级和压缩升级,不支持差分升级。
  • 3322 平台配置支持差分升级,但未启用升级镜像解密能力。ReRncFlag 必须保持为 0

端到端升级流程

FOTA 的完整链路如下图所示。构建服务器生成升级包后,可由升级服务器或本地计算机下发到设备。设备接收完整升级包并校验通过后进入本地升级流程,升级结束后重新启动到新版本。

端到端升级流程

图 1 FOTA 端到端升级流程

设备侧的标准操作顺序如下:

  1. 初始化升级模块:系统启动时调用 uapi_upg_init 注册内存管理和日志输出函数。
  2. 获取存储能力:调用 uapi_upg_get_storage_size 获取升级包可用空间。
  3. 准备升级存储:在传输开始前调用 uapi_upg_prepare,传入完整升级包长度。
  4. 保存升级包:将升级包直接上传到固定路径,或按连续偏移分包调用写入接口。
  5. 申请升级:调用 uapi_upg_request_upgrade 校验升级包并写入升级标记。
  6. 执行本地升级:设备重启进入 Recovery,由 Recovery 再次初始化升级模块并调用 uapi_upg_start
  7. 确认结果:升级完成后读取升级状态和结果,并检查应用版本、关键业务与设备日志。

diting-community 应用已在系统启动阶段初始化 Upgrade 模块。因此,应用 Demo 调用 uapi_upg_init() 时,应同时将 ERRCODE_SUCCERRCODE_UPG_ALREADY_INIT 视为可继续状态。将 Demo 移植到未集成系统初始化流程的目标时,必须注册有效的 mallocfree 函数。

升级包制作原理

升级包由 Key Area、FOTA Info Area、镜像哈希表和一个或多个镜像数据区组成。制作工具根据 fota.cfg 中的签名、版本、镜像 ID 和升级模式配置处理镜像,再生成统一的 update.fwpkg

升级包制作原理

图 2 升级包制作流程

数据区域 主要内容 作用
FOTA Key Area 密钥算法、密钥版本、二级公钥和签名 建立升级包验签所需的信任信息
FOTA Info Area 升级包版本、硬件 ID、镜像数量和哈希表摘要 描述升级包整体属性
镜像哈希表 镜像 ID、位置、长度和镜像头哈希 定位并校验升级包中的各镜像
镜像数据区 镜像头、完整镜像、压缩数据或差分数据 提供实际写入目标分区的数据

参数与配置说明

FOTA 相关的主要配置文件如下:

配置文件 说明 修改建议
src/build/config/target_config/3322/build_3322_update.py 配置新旧镜像路径、参与升级的镜像列表和输出目录 根据构建目标配置对应的镜像输出路径
src/build/config/target_config/3322/fota/fota.cfg 配置签名方式、升级包版本、镜像 ID、升级模式和防回滚版本 修改前备份;镜像配置必须与目标设备一致
src/middleware/chips/3322/include/shared/upg_config.h 配置设备侧升级能力 应与升级包制作配置匹配
src/middleware/chips/3322/include/shared/upg_common_porting.h 定义板端升级包和资源索引路径 默认升级包路径为 /user/update/update.fwpkg

diting-community 目标通过 CONFIG_OTA_UPDATE_SUPPORT 启用 Upgrade 模块,并通过 CONFIG_ENABLE_FOTA_SAMPLE 编译本文配套 Demo。移植到其他目标时,应同时检查 Upgrade 组件、Recovery 镜像、分区配置和 FOTA Demo 组件是否参与构建。

常用升级包参数如下:

参数 默认值或可选值 说明
SignSuite 4 默认使用 SHA-256 非安全校验格式;量产产品应根据安全方案选择签名配置和密钥
KeyAlg 0x2A13C856 与默认 SignSuite=4 对应的 SHA-256 ECC256 格式
Version 0x00000000 FOTA 信息区版本号
version_ext 0x00000000 单镜像防回滚版本号
version_mask 0x00000000 单镜像防回滚版本掩码
DecompressFlag 00x3C7896E10x44494646 分别表示全量、压缩和差分升级
ReRncFlag 0 升级镜像加密标志;当前平台保持为 0

当前 fota.cfg 中常用镜像 ID 如下:

镜像名称 镜像 ID 支持的升级模式
ssb 0x4B1E3C2D 全量、压缩;不建议加入应用侧常规 FOTA 升级包
seliteos 0x4BE10F2D 全量、压缩
recovery 0x4B69872D 全量、压缩、差分
application 0x4B0F2D2D 全量、压缩、差分
bt 0x4BF01E2D 全量、压缩、差分
dsp_main 0x5A87A52D 全量、压缩、差分
dsp_overlay 0x5A87A54B 全量、压缩、差分
nv 0xCB9E063C 仅全量;当前 3322 产品配置未开启 NV 升级能力
res_index 0xCB9E0826 全量、压缩
res_data 0xCB9E0832 全量、压缩

注意事项:当前非 Recovery 镜像启用了防回滚校验。制作升级包时,不应将镜像版本号配置为低于设备允许的版本;量产版本的版本号和版本掩码应由产品安全策略统一管理。

API 接口列表

本文档示例流程使用的接口如下:

接口函数 说明
uapi_upg_init 初始化升级模块并注册内存管理函数
uapi_upg_get_storage_size 获取升级包可用存储空间
uapi_upg_prepare 根据升级包总长度准备本地存储
uapi_upg_write_package_sync 按偏移同步写入升级包分片
uapi_upg_write_package_async 按偏移异步写入升级包分片
uapi_upg_read_package 从本地存储读取升级包数据
uapi_upg_request_upgrade 校验升级包、设置升级标记并按需重启
uapi_upg_start 执行本地升级
uapi_upg_register_progress_callback 注册升级进度回调
uapi_upg_get_status 获取当前升级状态
uapi_upg_get_result 获取升级结果和最后处理的镜像序号
uapi_upg_reset_upgrade_flag 清除升级标记,为下一次升级恢复状态

完整 API 列表

更多 FOTA 接口请参考:Upgrade API 参考


快速跑通 FOTA Demo

功能说明

本 Demo 使用 diting-communityapplication_signed.bin 制作单应用全量升级包,再通过 DebugKits 将升级包上传到设备。Demo 提供升级状态查询、存储准备、升级申请、升级标记清理和传输层分包写入接口。应用侧申请升级后,设备重启进入 Recovery 完成镜像更新。

验证项 Demo 行为
升级对象 application 镜像
升级模式 全量升级
升级包名称 update.fwpkg
板端路径 /user/update/update.fwpkg
完整性校验 申请升级时执行整包校验,升级时再次校验镜像
预期结果 Recovery 升级成功,设备重启运行新应用版本

配套 AT 命令如下:

命令 说明
AT+FOTASTATUS 查询 Demo 状态、存储空间、升级状态和上次升级结果
AT+FOTABEGIN=<package_len> 使用升级包完整长度准备本地存储
AT+FOTAREQUEST=<reset> 校验升级包并申请升级;reset=1 时申请成功后立即重启
AT+FOTARESETFLAG 清除升级标记并恢复 Demo 上下文

准备工作

说明: 本文示例命令以一站式 CLI 为主。实际开发可从以下三种环境中选择,推荐使用一站式 CLI。

开发环境 适用场景 使用指南
一站式 CLI(推荐) 快速完成目标选择、构建、烧录和串口监视 一站式 CLI 开发环境使用指南
HiSpark Studio for VS Code 图形化编辑、编译、烧录和调试 HiSpark Studio for VS Code 开发环境使用指南
WSL 与 Docker 在 Windows 上使用一致的 Linux 容器构建环境 WSL 与 Docker 环境使用指南
  1. 按照一站式CLI开发环境使用指南完成环境安装,并确认 fbb doctor 检查通过。
  2. 准备一块已烧录基线版本的 HiDiTing 开发板,并记录基线应用的版本信息或可观察行为。
  3. 确认目标配置已包含 CONFIG_OTA_UPDATE_SUPPORTCONFIG_ENABLE_FOTA_SAMPLE,Recovery 镜像和分区表已正确烧录。
  4. 准备 DebugKits,并通过调试串口连接开发板。
  5. 开发验证阶段可使用 SDK 默认测试密钥;量产环境必须替换为产品密钥,并按安全规范保护私钥。

编译

在工程目录中设置 diting-community 打包目标并执行编译:

# 设置默认编译目标
fbb set-target pack_diting_community

# 编译固件
fbb build

编译成功后,完整固件位于:

output/3322/fwpkg/diting-community.fwpkg

用于制作 FOTA 升级包的应用镜像位于:

output/3322/acore/diting-community/application_signed.bin

首次验证 FOTA 前,先使用一站式 CLI 将该构建对应的完整基线固件烧写到开发板,并打开 UART2 日志串口;将 COM3 替换为实际端口:

fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000

后续 FOTA 验证传输的是升级包,不需要为每次升级重复整包烧写。

制作升级包

  1. 检查 src/build/config/target_config/3322/build_3322_update.py 中的 self.app_binditing-community 应使用以下输出路径:

    self.app_bin = os.path.join(
        self.output, "acore", "diting-community", "application_signed.bin"
    )
    

    如果产品使用其他构建目标,应将该路径调整为对应目标的实际输出目录。

  2. 保持 get_new_image() 中仅启用 application

    def get_new_image(info):
        image_list = []
        image_list.append("=".join([info.app_bin, "application"]))
        return "|".join(image_list)
    
  3. 确认 src/build/config/target_config/3322/fota/fota.cfg[application] 使用全量模式:

    [application]
    HeaderMagic=0x464F5451
    ImageId=0x4B0F2D2D
    DecompressFlag=0x0
    ReRncFlag=0x0
    version_ext=0x00000000
    version_mask=0x00000000
    
  4. 在 SDK 的 src 目录执行升级包制作脚本:

    Linux:

    python3 build/config/target_config/3322/build_3322_update.py
    

    Windows:

    python build\config\target_config\3322\build_3322_update.py
    

    说明:SDK 当前提供 Linux 和 Windows 版本的签名、压缩工具。macOS 主机请在受支持的 Linux 构建环境中执行升级包制作流程。

  5. 确认生成以下文件:

    output/3322/upgrade/update.fwpkg
    
  6. 在 Linux 构建环境中获取升级包的完整字节数,后续调用 AT+FOTABEGIN 时必须使用该值:

    stat -c %s output/3322/upgrade/update.fwpkg
    

使用方式

  1. 执行 AT+FOTASTATUS,确认命令可用且 storage 不小于升级包长度。
  2. 根据 update.fwpkg 的完整字节数执行 AT+FOTABEGIN=<package_len>。命令返回 OK 后再上传文件。
  3. 在 DebugKits 的 System 插件中选择“上传文件”。
  4. 本地文件选择 output/3322/upgrade/update.fwpkg
  5. 板端文件路径填写 /user/update/update.fwpkg,单击“Upload”并等待进度达到 100%。

    板端文件路径填写 <code>/user/update/update.fwpkg</code>,单击“Upload”并等待进度达到 100%

    图 3 使用 DebugKits 上传升级包

  6. 文件接收完成后执行 AT+FOTAREQUEST=1。命令校验升级包并写入升级标记,申请成功后设备立即重启;串口可能在输出最终 OK 前断开。

  7. Recovery 初始化升级模块后自动检查升级标记,并调用 uapi_upg_start() 完成本地升级。

说明:调试阶段可先执行 AT+FOTAREQUEST=0 完成校验和升级申请,再通过受控方式手动复位。需要放弃尚未执行的升级请求时,执行 AT+FOTARESETFLAG 清除升级标记。

说明:SDK 中的 DFX 更新测试还提供分包写入验证路径。该测试先将源文件放到 /user/test/update.fwpkg,再按连续偏移调用 uapi_upg_write_package_sync() 写入升级存储。该路径仅用于验证分包保存流程,不应与正式升级包固定路径 /user/update/update.fwpkg 混用。

预期结果

  1. 升级包制作脚本执行成功,在 output/3322/upgrade 生成 update.fwpkg
  2. DebugKits 上传进度达到 100%,板端可访问 /user/update/update.fwpkg
  3. uapi_upg_request_upgrade() 返回 ERRCODE_SUCC,设备重启进入 Recovery。
  4. Recovery 日志显示检测到升级请求并开始处理 application 镜像。
  5. 升级完成后设备再次重启,运行新版本应用。
  6. uapi_upg_get_status() 返回升级成功状态,或 uapi_upg_get_result() 返回 UPG_RESULT_UPDATE_SUCCESS

文件结构与代码走读

文件结构

FOTA Demo、打包工具、接口、设备适配和运行实现位于以下路径:

samples/native_samples/fota/
├── CMakeLists.txt                        # fota_sample 组件配置
├── fota_demo.h                           # 状态、信息结构和传输层接口
├── fota_demo.c                           # FOTA 状态机与 Upgrade UAPI 调用
└── fota_demo_at.c                        # FOTA AT 命令注册与处理

src/
├── build/config/target_config/3322/
│   ├── build_3322_update.py             # 3322 升级包制作入口
│   └── fota/fota.cfg                    # 升级包格式、签名和镜像配置
├── build/script/
│   └── build_upg_pkg.py                 # 通用升级包制作逻辑
├── include/middleware/utils/
│   └── upg.h                            # FOTA 对外接口与数据结构
└── middleware/
    ├── chips/3322/
    │   ├── include/shared/
    │   │   ├── upg_config.h             # 3322 升级能力配置
    │   │   └── upg_common_porting.h      # 板端文件路径等适配配置
    │   └── update/                       # 3322 存储、备份和公共适配
    └── utils/
        ├── dfx/diag_dfx_cmd/diag_update/
        │   └── diag_update.c             # DFX 升级命令与分包写入示例
        └── update/
            ├── common/                   # 升级公共逻辑与校验
            ├── storage/                  # 升级包存储和升级申请
            └── local_update/             # 全量、压缩、差分和资源升级

各文件职责

文件 职责 关键内容
/samples/native_samples/fota/fota_demo.c 实现传输无关的 FOTA 状态机 初始化、准备、连续写入、升级申请、状态查询和标记清理
/samples/native_samples/fota/fota_demo_at.c 提供开发板调试入口 AT+FOTASTATUSAT+FOTABEGINAT+FOTAREQUESTAT+FOTARESETFLAG
/samples/native_samples/fota/fota_demo.h 定义 Demo 对外接口 状态枚举、查询结构和传输层调用接口
/samples/native_samples/fota/CMakeLists.txt 定义 fota_sample 构建组件 源文件、头文件路径、AT 接入宏和整库链接
build_3322_update.py 选择升级镜像并生成 update.fwpkg upg_base_infoget_new_image()get_old_image()
fota.cfg 定义升级包和各镜像属性 SIGN_CFGFOTA_KEY_AREAFOTA_INFO_AREADecompressFlag
upg.h 提供应用和 Recovery 可调用的 FOTA UAPI 初始化、保存、申请、启动、状态和校验接口
upg_config.h 定义当前产品支持的升级能力 验签、差分、防回滚、文件系统和资源文件支持
upg_common_porting.h 提供板级路径定义 UPG_FILE_NAMEUPG_RES_INDEX_PATH
upg_storage.c 管理升级包保存、升级标记和升级申请 uapi_upg_prepare()uapi_upg_write_package_sync()uapi_upg_request_upgrade()
upg_process.c 执行升级包校验和镜像更新 uapi_upg_start()
upg_verify.c 校验包头、哈希表和镜像 包头校验、签名校验、镜像校验
diag_update.c 展示分包写入和升级命令接入方式 连续偏移写入、升级请求和本地升级

代码走读

升级包制作入口

build_3322_update.py 通过 get_new_image() 选择升级包包含的新镜像;仅在制作差分升级包时,才需要在 get_old_image() 中提供严格匹配的旧版本镜像。脚本最终调用通用打包逻辑,在 output/3322/upgrade 目录生成 update.fwpkg

conf = get_parameters()
conf.app_name = "update"
conf.upg_format_path = info.fota_format_path
conf.base = info.fota_cfg
conf.new_images = get_new_image(info)
conf.old_images = get_old_image(info)
conf.output_dir = info.upg_output
begin(conf)

升级模块初始化

标准应用在 CONFIG_OTA_UPDATE_SUPPORT 打开时初始化升级模块。mallocfree 为必选函数,serial_putc 为可选日志输出函数。

upg_func_t upg_func = {0};
upg_func.malloc = upg_malloc;
upg_func.free = upg_free;
upg_func.serial_putc = upg_putc;

errcode_t ret = uapi_upg_init(&upg_func);
if (ret != ERRCODE_SUCC && ret != ERRCODE_UPG_ALREADY_INIT) {
    /* 记录初始化失败日志并退出升级流程 */
}

应用和 Recovery 属于不同程序,均需要在各自启动流程中初始化升级模块。

准备并写入升级包

分包传输时,应先传入完整升级包长度完成准备,再按从 0 开始的连续偏移写入。下一包偏移必须等于上一包的 offset + len。根据 upg.h 的接口约束,写入偏移和分片长度均应按 4 字节对齐。

errcode_t fota_begin(uint32_t package_len)
{
    if (package_len == 0 || package_len > uapi_upg_get_storage_size()) {
        return ERRCODE_UPG_INVALID_PARAMETER;
    }

    upg_prepare_info_t info = {
        .package_len = package_len,
    };
    return uapi_upg_prepare(&info);
}

errcode_t fota_write(uint32_t offset, const uint8_t *data, uint16_t len)
{
    if (data == NULL || len == 0 || (offset % 4) != 0 || (len % 4) != 0) {
        return ERRCODE_UPG_INVALID_PARAMETER;
    }
    return uapi_upg_write_package_sync(offset, data, len);
}

申请并执行升级

升级包完整保存后,在应用侧调用 uapi_upg_request_upgrade()。当 resettrue 时,申请成功后设备重启;Recovery 检测到升级标记后调用 uapi_upg_start()

errcode_t fota_request(void)
{
    errcode_t ret = uapi_upg_request_upgrade(true);
    if (ret != ERRCODE_SUCC) {
        /* 整包校验或升级标记设置失败,记录 ret */
        return ret;
    }

    /* 申请成功后进入重启流程,正常情况下不会继续执行业务代码 */
    return ERRCODE_SUCC;
}

uapi_upg_start() 是阻塞接口,升级期间不应在同一执行上下文中运行其他耗时业务。标准产品通常在 Recovery 或专用升级线程中执行该接口。

查询升级状态和结果

升级完成并重新启动应用后,可读取升级状态和结果,用于日志记录或界面提示:

void fota_print_result(void)
{
    upg_result_t result = UPG_RESULT_MAX;
    uint32_t last_image_index = 0;

    if (uapi_upg_get_result(&result, &last_image_index) == ERRCODE_SUCC) {
        /* 输出 result 和 last_image_index,或上报到设备管理平台 */
    }
}

基于 FOTA Demo 开发应用

代码清单

配套 Demo 已按以下结构接入 samples/native_samples/fota

samples/native_samples/fota/
├── CMakeLists.txt                 # fota_sample 组件构建配置
├── fota_demo.c                    # 升级状态机和 Upgrade UAPI 调用
├── fota_demo.h                    # 对外接口与状态定义
└── fota_demo_at.c                 # 可选的 AT 串口回归入口
文件 职责
fota_demo.c 初始化升级模块,检查空间,准备存储,接收数据,申请升级、清除标记和记录结果
fota_demo.h 定义 fota_demo_init()fota_demo_begin()fota_demo_write()fota_demo_request() 等接口
fota_demo_at.c 可选地将状态查询、存储准备、升级申请和标记清理封装为 AT 命令
CMakeLists.txt 声明核心源文件、头文件路径和组件链接配置;需要串口回归时再纳入 AT 适配文件和注册宏

升级状态机设计

产品 FOTA 模块应使用显式状态机,避免重复准备、乱序写入或在升级过程中再次触发升级:

状态 允许操作 成功后的下一状态
IDLE 查询空间并调用 fota_demo_begin() PREPARED
PREPARED 通过 DebugKits 上传固定路径文件,或提交首个分片 PREPAREDRECEIVINGREADY
RECEIVING 按连续且 4 字节对齐的偏移写入升级包分片 RECEIVINGREADY
READY 校验累计接收长度并申请升级 REQUESTED
REQUESTED 等待重启进入 Recovery 设备重启后由 uapi_upg_get_status()uapi_upg_get_result() 反映结果
FAILED 保存错误码并执行 fota_demo_reset() IDLE

CMakeLists.txt 示例

FOTA Demo 的组件配置如下:

set(COMPONENT_NAME "fota_sample")

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/fota_demo.c
)

set(PUBLIC_HEADER
    ${CMAKE_CURRENT_SOURCE_DIR}
)

set(PRIVATE_HEADER
    ${ROOT_DIR}/src/include
    ${ROOT_DIR}/src/include/middleware/utils
)

set(PUBLIC_DEFINES "")

set(WHOLE_LINK true)
set(MAIN_COMPONENT false)

build_component()

产品业务应在下载任务或升级服务中依次调用 fota_demo_init()fota_demo_begin()fota_demo_write()fota_demo_request()。只有需要复用当前 Demo 的串口回归方式时,才把 fota_demo_at.c 加入 SOURCES、补充 AT 私有头文件目录并定义 AT_DITING_EXAMPLE_FOTA;AT 入口不是升级状态机的一部分。

关键代码片段

产品传输层应将接收到的数据转换为连续的 offset + data + len 分片,并调用 Demo 接口:

errcode_t product_fota_receive(uint32_t offset, const uint8_t *data, uint16_t len)
{
    return fota_demo_write(offset, data, len);
}

fota_demo_write() 内部检查 Demo 状态、连续偏移、4 字节对齐和累计长度。全部分片写入后,调用 fota_demo_request(true) 申请升级并立即重启。

如果使用异步写入接口,必须等待写完成回调返回成功后再提交下一包:

static void fota_write_done(errcode_t result)
{
    if (result == ERRCODE_SUCC) {
        /* 通知传输任务发送或提交下一包 */
    } else {
        /* 停止接收并记录失败结果 */
    }
}

测试验证

  1. 正常升级:从基线版本升级到更高版本,确认版本和业务功能正确。
  2. 重复升级:重复下发相同升级包,确认产品策略能够拒绝或安全处理。
  3. 降级测试:下发低版本升级包,确认防回滚策略生效。
  4. 断点测试:分别在下载、校验和镜像更新阶段模拟断电,确认设备可恢复或重新进入升级。
  5. 损坏包测试:修改升级包任意字节,确认整包校验失败且不会写入目标镜像。
  6. 空间边界:测试等于、接近和超过可用空间的升级包。
  7. 乱序数据:故意提交错误偏移,确认 Demo 拒绝写入并保留错误日志。
  8. 多镜像测试:对应用、Recovery、资源文件等组合包逐项确认升级结果。

注意事项

  • 升级包路径固定:文件系统模式下,正式升级包使用 /user/update/update.fwpkg。文件名或路径不一致会导致升级模块无法读取升级包。
  • 准备操作必须在传输前完成:调用 uapi_upg_prepare() 时必须传入完整且非 0 的升级包长度。
  • 分包必须连续写入:写入偏移应从 0 开始连续递增,不得乱序、重复或跳过数据。
  • 分包必须满足对齐要求:调用同步或异步写入接口时,分片偏移和长度应按 4 字节对齐;升级包制作和传输协议应保证最后一个分片同样满足该要求。
  • 异步写入不得并发:只有收到上一次异步写完成回调且结果成功后,才能写入下一包。
  • 校验失败不得强制升级uapi_upg_request_upgrade() 返回失败时,应删除或覆盖错误升级包,不得绕过校验设置升级标记。
  • 升级过程中保持供电稳定:进入本地升级后不支持业务侧取消。虽然平台支持升级进度恢复,仍应避免断电和看门狗异常复位。
  • 进度回调保持轻量:进度回调中只更新状态或发送事件,不得执行阻塞 I/O、动态加载或长时间日志输出。
  • 差分包严格绑定旧版本:差分包只能用于制作时指定的旧镜像版本。旧镜像不匹配会导致校验或差分恢复失败。
  • 版本号单调递增:启用防回滚后,新包的镜像版本不得低于设备允许版本。版本掩码应由产品统一管理。
  • 私钥不得随产品发布:SDK 内的默认私钥仅用于开发验证。量产密钥应离线保存,并在受控环境中完成签名。
  • 镜像能力必须匹配:NV 仅支持全量升级;资源文件不支持差分升级;当前平台未开启升级镜像解密能力。
  • 不得升级分区表:普通 FOTA 包不应包含分区表。升级前应确认现有分区布局能够容纳新镜像和升级包。
  • 谨慎升级启动链镜像:SSB 等启动链镜像失败可能影响设备启动,普通应用升级不建议包含此类镜像。
  • 资源升级预留索引空间:资源索引文件与升级包共享存储空间时,需要为 res_index.bin 留出空间;资源文件数量较多时应提前做容量和性能验证。
  • 先验证再批量发布:升级包应在目标硬件、目标基线版本和量产分区配置上完成灰度验证后再发布。

常见编译错误

现象或错误码 常见原因 处理方法
build_3322_update.py 提示镜像不存在 self.app_bin 与当前构建目标不一致,或目标固件尚未编译 确认路径为 output/3322/acore/diting-community/application_signed.bin,并先执行 fbb build
打包工具或 LZMA 工具不存在 SDK 子模块或工具链未完整下载 更新 SDK 子模块,并执行 fbb doctor 检查环境
Python 模块导入失败 未在 SDK src 目录执行,或 Python 环境不完整 回到 src 目录执行脚本,并使用一站式 CLI 环境提供的 Python
CMake 找不到 upg.h Demo 的私有头文件路径或组件依赖未配置 增加 ${ROOT_DIR}/src/include/middleware/utils,并确认升级组件加入当前目标
链接阶段提示 uapi_upg_* 未定义 目标未启用 OTA 更新组件 确认目标配置包含 CONFIG_OTA_UPDATE_SUPPORT 和 Upgrade 相关组件后重新编译
AT+FOTASTATUS 等命令不存在 FOTA Demo 未参与构建或 AT 注册入口未执行 检查 CONFIG_ENABLE_FOTA_SAMPLEfota_sampleAT_DITING_EXAMPLE_FOTA
CMake 提示 Function missing ending ")" CMakeLists.txt 括号不完整或混用了异常行结束符 检查报错行附近的 set()/if(),并统一文件行结束符后重新配置
ERRCODE_UPG_NOT_INIT (0x80003040) 调用其他升级接口前未执行 uapi_upg_init() 在应用和 Recovery 各自的初始化阶段调用 uapi_upg_init()
ERRCODE_UPG_ALREADY_INIT (0x80003041) 同一程序重复初始化升级模块 统一初始化入口;将该返回值作为已初始化状态处理
ERRCODE_UPG_INVALID_PARAMETER (0x80003042) 包长为 0、参数为空、长度越界或状态不匹配 检查 package_len、数据指针、分片长度和当前状态
ERRCODE_UPG_NOT_PREPARED (0x80003054) 未完成存储准备,或 Demo 状态不允许写入和申请升级 先执行 AT+FOTABEGIN=<package_len>,再传输完整升级包
ERRCODE_UPG_INVALID_BUFF_LEN (0x80003055) 分片长度为 0 或不符合传输约束 确保数据非空,并按 4 字节对齐分片长度和偏移
ERRCODE_PARTITION_CONFIG_NOT_FOUND (0x80003003) 分区表未烧录或缺少 FOTA 相关分区 重新烧录与当前固件匹配的分区表,并核对分区 ID
升级包长度未超过分区容量,但仍提示空间不足 设备残留旧升级包或资源索引占用空间 删除旧升级包,重新查询可用空间,并为资源索引预留容量
ERRCODE_UPG_FILE_OPEN_FAIL (0x80003057) 文件不存在、路径错误或文件系统未挂载 检查 /user/update/update.fwpkg、目录权限和文件系统状态
ERRCODE_UPG_FILE_WRITE_FAIL (0x80003058) 空间不足、写入中断或文件系统异常 检查剩余空间,删除旧文件并重新传输升级包
ERRCODE_UPG_FILE_SEEK_FAIL (0x80003059) 分包偏移错误或文件损坏 确保分包连续写入并从偏移 0 重新开始
ERRCODE_UPG_FILE_READ_FAIL (0x80003060) 升级包未完整上传或文件读取异常 比对文件长度,重新上传并再次申请升级
ERRCODE_UPG_NOT_NEED_TO_UPDATE (0x80003047) 未检测到有效升级标记或升级包不完整 确认 uapi_upg_request_upgrade() 已成功,检查升级标记和包完整性
升级包校验失败 传输损坏、密钥或算法不匹配、镜像 ID 不匹配、包不属于当前设备 重新传输,核对 SignSuiteKeyAlg、硬件 ID、镜像 ID 和目标版本
防回滚校验失败 version_ext 低于设备允许版本,或版本掩码配置错误 使用更高版本重新制作升级包,核对产品版本策略
差分恢复失败 设备旧镜像与打包时使用的旧镜像不一致 使用正确基线镜像重新制作差分包,或改用全量升级包
资源索引创建失败 升级包占满可用空间,没有为 res_index.bin 预留容量 减小升级包或调整存储布局,确保索引和资源数据均可落盘

调试建议:

  1. 优先记录每个 Upgrade UAPI 的十六进制返回值、升级包长度、当前偏移和已接收长度。
  2. 打包失败时检查 output/3322/upgrade/temp_dir 中的中间文件和脚本输出。
  3. 申请升级前比对计算机端与设备端的文件大小;必要时增加摘要校验。
  4. 升级失败后调用 uapi_upg_get_result(),结合 last_image_index 定位失败镜像。
  5. 对差分、压缩和多镜像升级,先分别验证单镜像全量包,再逐步增加复杂度。
  6. 使用 fota_demo_write() 时同时记录期望偏移和实际偏移,优先排查乱序、重复和未对齐分片。