ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Flipper Zero OTA 更新机制全解析:RAM 引导、更新清单与固件包构建实战

Flipper Zero OTA 更新机制全解析:RAM 引导、更新清单与固件包构建实战 Flipper Zero OTA 更新机制全解析RAM 引导、更新清单与固件包构建实战【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware本篇文章围绕 Flipper Zero 固件的 OTAOver-The-Air更新机制展开系统讲解其从 RAM 执行引导代码、三阶段更新流程、update.fuf更新清单格式到使用fbt与scripts/update.py构建完整/最小/自定义更新包的完整技术细节。读完本文你将掌握 Flipper Zero 固件更新的底层原理并能独立构建、定制和排查 OTA 更新包。一、OTA 更新的基础从 RAM 执行代码Flipper Zero 的 OTA 机制建立在一个特殊的引导模式之上固件包含一个特殊的启动模式该模式会把一份经过特殊构建的系统镜像加载进 RAM并将控制权转交给它。这段在 RAM 中执行的系统镜像对 Flipper 的整块 Flash 存储器拥有完整的写权限——而这是当主代码与要修改的 Flash 处于同一存储介质时无法做到的。这种从 RAM 执行代码的能力正是 OTA 固件更新的基石它使得固件能够安全地重写自身所在的 Flash 区域并且还能对运行在**第二颗 MCU 内核Core2**上的无线电协议栈Radio Stack执行升级操作。从源码结构看updater 本身就是一个独立的应用位于 applications/system/updater并包含独立的 CLI 入口applications/system/updater/cli/updater_cli.c与场景管理applications/system/updater/scenes/updater_scene.c。构建系统通过FIRMWARE_BUILD_CFGupdater与RAM_EXECTrue两个配置区分普通固件与 updater 镜像并为 updater 编译时定义FURI_RAM_EXEC宏参见 firmware.scons。在 applications/system/updater/updater.c 中可以看到在 RAM 执行模式下FURI_RAM_EXECupdater 启动后直接进入主更新场景而在普通固件中只有 RTC 引导模式为FuriHalRtcBootModePreUpdate/FuriHalRtcBootModePostUpdate时才触发更新流程。二、Flipper OTA 更新如何工作三阶段流程安装 OTA 更新包需要经过 3 个阶段1. 备份内部存储/int/int是 Flipper Flash 存储器上一个特殊的分区它占用了固件代码未使用的全部剩余空间。由于新版本固件的大小可能不同直接安装会导致 Flash 重新分区并造成数据丢失。因此在对固件采取任何操作之前系统会先把当前配置从/int备份为一个纯 tar 归档文件存放到 SD 卡上。该逻辑由 lib/update_util/int_backup.c 实现int_backup_create()调用storage_int_backup()完成备份int_backup_unpack()通过storage_int_restore()恢复。备份时还通过backup_name_converter()将蓝牙设置、桌面设置、通知设置、海豚状态等关键配置文件统一加上.前缀避免恢复时遗漏隐藏文件参见 int_backup.c。2. 执行设备更新主固件会先加载一份updater 镜像——这是主 Flipper 固件的定制构建版本——到 RAM 并运行它。updater 按照**更新清单Update Manifest**文件的描述对系统 Flash 执行操作。具体顺序如下Radio 协议栈更新可选如果更新包中捆绑了 Radio Stack 镜像updater 首先将其版本与当前安装的版本进行比较。如果不匹配updater 会先执行协议栈卸载deinstallation然后写入并安装新协议栈。安装本身由运行在 Core2 上的专有软件FUSFirmware Upgrade Service执行并会引发一系列系统重启。Option Bytes 校验与修正updater 会校验并纠正Option Bytes——这是包含 Flipper MCU 底层配置的特殊内存区域。固件烧写updater 加载要烧写的.dfu固件文件使用CRC32校验其完整性将其写入系统 Flash并对写入的数据进行验证。3. 恢复内部存储与更新资源对 Flash 存储执行完上述操作后系统会重启进入新烧写的固件并恢复先前备份的/int内容。如果更新包中还包含额外的资源归档Resources 归档则将其解压到 SD 卡上。三、更新清单Update Manifest更新包中附带一个描述其内容的清单文件。清单采用Flipper File Format——一种由键值对组成的简单文本文件。清单解析逻辑位于 lib/update_util/update_manifest.c所有键名常量在文件头部集中定义参见 update_manifest.c。必填字段Mandatory Fields更新清单必须按给定顺序包含以下键键含义Filetype常量字符串Flipper firmware upgrade configurationVersion清单版本当前值为2Info任意字符串描述包内容Target包所针对的硬件版本Loader从 RAM 执行的 stage 2 loader 文件名Loader CRCloader 文件的 CRC32注意以**小端十六进制little-endian hex**表示在 update_manifest.c 中可以看到清单的校验正是依次读取 headerFiletype Version、Info、Target、Loader和Loader CRC任何一个读取失败或 Filetype 不匹配都会使整个清单被判为无效valid false。可选字段Optional Fields其他字段可以为空值。此时 updater 会跳过所有与这些值相关的操作键含义RadioSTM 提供的 radio stack 镜像文件名Radio addressradio stack 的安装地址由 STM 在 Release Notes 中给出Radio versionradio 的主版本号、次版本号、子版本号以及分支branch、发布release和协议栈类型stack type打包为 6 个十六进制编码字节Radio CRCradio 镜像的 CRC32Resources要解压到 SD 卡的 TAR 归档文件名OB reference、OB mask、OB write mask用于校验和纠正 Option Bytes 的参考值Radio version 的 6 字节结构在 lib/update_util/update_manifest.h 中有明确定义major、minor、sub、branch、release、type各占一个字节并通过_Static_assert强制该联合体大小为 6 字节。OBOption Bytes相关字段并非简单读取即可update_manifest_has_obdata()update_manifest.c还会执行多项健全性检查包括验证 write mask / compare mask 中相邻字的掩码值一致性以及参考值中不存在未掩码的位。这一点与清单生成时写入的注释相呼应——在 scripts/update.py 中写入 OB 字段前会输出警告NEVER EVER MESS WITH THESE VALUES, YOU WILL BRICK YOUR DEVICE切勿乱动这些值否则设备将变砖。四、OTA 更新错误码OTA 更新过程被设计得尽可能故障安全fail-safe。在启动任何有风险的操作之前updater 会先验证所有相关数据确保设备不会停留在部分更新或变砖的状态。即使出现问题updater 也允许重试失败的操作并通过错误码报告其状态。错误码采用[XX-YY]格式其中XX编码失败的操作阶段YY包含错误发生时具体进度的附加细节阶段描述代码进度描述加载更新清单113Updater 报告硬件版本不匹配20无法获取已保存的清单路径30清单加载失败40不支持的更新包版本50包的硬件目标不匹配60缺少 DFU 文件80缺少 radio 固件文件备份配置20-100FS 读写错误检查 radio 固件30-99读取 radio 固件文件出错100CRC 不匹配卸载 radio 固件40SHCI Delete 命令错误80等待命令状态出错写入 radio 固件50-100块读写错误安装 radio 固件610SHCI Install 命令错误80等待命令状态出错Core2 忙710无法启动 C220将 C2 切换到 FUS 模式失败30FUS 操作出错50将 C2 切换到协议栈模式失败校验 Option Bytes8yyOption Byte 错误码检查 DFU 文件90打开 DFU 文件出错1-98读取 DFU 文件出错99-100DFU 文件损坏写入 Flash100-100块读写错误验证 Flash110-100块读写错误恢复配置120-100FS 读写错误更新资源13-150-100SD 卡读写错误这些错误码对应的阶段描述字符串在固件侧有完整定义见 applications/system/updater/util/update_task.c如 Loading update manifest、Checking DFU file、Writing flash、Core 2 busy 等而阶段到进度区间的映射则在 update_task.c 的错误细节表中定义——例如进度 0-13 对应 Wrong Updater HW、41-50 对应 HW Target mismatch 等。注意表中部分条目由#ifndef FURI_RAM_EXEC宏区分非 RAM 执行环境普通固件包含 FS R/W error 等阶段而 RAM 执行环境updater则替换为 CRC mismatch、Stack remove: cmd error 等更细粒度描述。五、构建更新包完整包Full Package构建包含固件、radio stack 和 SD 卡资源的完整更新包运行./fbt COMPACT1 DEBUG0 updater_package最小包Minimal Package构建仅包含固件的最小更新包运行./fbt COMPACT1 DEBUG0 updater_minpackage从构建脚本 SConstruct 可以看到这两个目标的实现updater_package通过DistCommand组合了固件资源清单、radio 参数--radio/--radiotype/--obdata/--stackversion、资源目录-r以及可选的启动闪屏--splash而updater_minpackage仅传入基本的版本信息。此外还可以使用updater_debug/updater_blackmagic目标对 updater 进行调试并通过flash_usb_full/flash_usb通过 USB 与 CLI 直接安装更新包见 SConstruct。定制更新包Customizing Update Bundles默认更新包使用Bluetooth Light 协议栈构建。如果你的固件版本支持其他协议栈可以通过向fbt传递协议栈类型和二进制文件名来构建./fbt updater_package COMPACT1 DEBUG0 COPRO_OB_DATAscripts/ob_custradio.data COPRO_STACK_BINstm32wb5x_BLE_Stack_full_fw.bin COPRO_STACK_TYPEble_full注意COPRO_OB_DATA必须指向scripts文件夹中一个有效文件该文件包含与你的 radio stack 类型匹配的参考 Option Byte 数据。某些情况下你可能需要在构建命令行中加上COPRO_DISCLAIMER...来确认意图。构建部分更新包Building Partial Update Packages你可以通过直接调用 scripts/update.py 来自定义包内容。例如构建一个仅安装 BLE FULL 协议栈的包scripts/update.py generate \ -t f7 -d r13.3_full -v BLE FULL 13.3 \ --stage dist/f7/flipper-z-f7-updater-*.bin \ --radio lib/stm32wb_copro/firmware/stm32wb5x_BLE_Stack_full_fw.bin \ --radiotype ble_full完整的选项列表请查看scripts/update.py generate的帮助信息。六、深入源码update.py 的生成逻辑与安全检查scripts/update.py 是构建更新包的底层实现其generate子命令承担核心工作理解它对定制更新包至关重要清单版本与文件命名清单版本固定为2UPDATE_MANIFEST_VERSION 2最终清单文件名为update.fufUPDATE_MANIFEST_NAMEstage2 loader 统一重命名为updater.bin固件为firmware.dfuradio 为radio.bin资源归档为resources.thsupdate.py。协议栈类型白名单仅BLE_FULL、BLE_LIGHT、BLE_BASIC三种标准协议栈类型可直接打包WHITELISTED_STACK_TYPESupdate.py。捆绑非标准协议栈类型且未确认--I-understand-what-I-am-doingyes时脚本会拒绝生成并给出警告You are trying to bundle a non-standard stack type。radio 地址自动推导未显式指定--radioaddr时脚本会从 radio 镜像元数据中猜测加载地址并打印提示建议与 STM Release Notes 核对update.py。内存布局检查layout_check脚本会检查固件镜像是否与 Core2 协议栈区域重叠Firmware image overlaps C2 region and is not programmable!并校验固件与协议栈之间预留的 Flash 页数update.py。updater 体积阈值当 stage2 loader 超过128 * 1024字节UPDATER_SIZE_THRESHOLD时会发出警告——过大时旧版本固件无法加载它update.py。CRC 与字节序loader 与 radio 的 CRC32 通过zlib.crc32计算crc()并以小端十六进制写入清单int2ffhex()按字节对十六进制字符串做反向分块与文档中loader CRC 以小端十六进制表示的要求一致update.py。Radio version 打包copro_version_as_int()将主/次/子版本、分支、发布与协议栈类型按位移打包为 6 字节值update.py与清单Radio version字段的 6 字节定义对应。七、更新前准备固件侧的校验链在 updater 真正开始写 Flash 之前固件侧还会做一层预检prepare全部逻辑位于 lib/update_util/update_operation.c 的update_operation_prepare()update_operation.c其校验顺序是内部存储剩余空间/int空闲空间必须至少为UPDATE_MIN_INT_FREE_SPACE2 * 4 * 1024字节即至少 4 个空闲 LFS 页见 update_operation.c否则返回UpdatePrepareResultIntFull。清单文件存在性清单不存在则返回ManifestFolderNotFound。清单解析与版本检查调用update_manifest_init()解析清单版本低于UPDATE_OPERATION_MIN_MANIFEST_VERSION时返回OutdatedManifestVersion。硬件目标匹配仅当硬件目标已设置时比较预量产设备接受任意固件见注释 pre-production devices accept any firmware不匹配返回TargetMismatch。stage2 loader 存在性与 CRC 校验通过crc32_calc_file()计算实际 CRC 并与清单中的Loader CRC比对不匹配返回StageIntegrityError。清单路径持久化将清单路径写入 SD 卡根目录的.fupdate指针文件UPDATE_FILE_POINTER_FILE_NAME见 update_manifest.h并回读校验。设置引导模式全部通过后调用furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate)将 RTC 引导模式置为更新前设备重启后即进入更新流程。对应的准备结果枚举与描述字符串如 Invalid manifest name or location、Hardware target mismatch、Update package is too old、Need more free space in internal storage 等在 update_operation.c 中定义可用于在 CLI 侧定位预检失败原因。这套预检机制与 OTA 错误码共同构成了 Flipper Zero 更新链路中先验证、后操作的双层保护。结语Flipper Zero 的 OTA 更新体系是一个设计严谨的闭环以 RAM 执行镜像解决自更新自的根本矛盾以三阶段流程备份/int→ 更新设备 → 恢复配置与资源保证数据不丢失以清单文件加多层 CRC/版本/硬件校验保证不写入损坏数据最后以[XX-YY]错误码让任何失败都可定位、可重试。无论是使用现成的fbt目标一键构建完整或最小更新包还是通过scripts/update.py按需定制只含特定协议栈或资源的增量包本文所述的原理与命令都能帮助你安全地完成固件分发与设备升级。【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表