IOS-nRF-Toolbox Zephyr DFU实战:MCUmgr/SMP协议固件传输的iOS端完整实现
nRF Toolbox 是 Nordic Semiconductor 官方的 iOS 蓝牙低功耗(BLE)工具集 App,其中 Zephyr DFU 模块基于 MCUmgr/SMP 协议,为运行 Zephyr RTOS 的设备提供 OTA 固件升级能力。本文带你从新手视角,完整走通 Zephyr DFU 在 iOS 端的实现:如何把固件传到 iPhone、如何发起升级、源码又是如何组织的,一篇看完即可上手。
Zephyr DFU 与传统 Nordic DFU 的区别:为什么需要 MCUmgr
nRF Toolbox 内置了两种固件升级(DFU)方案:
| 对比项 | 传统 Nordic DFU | Zephyr DFU |
|---|---|---|
| 协议 | Nordic 自定义 DFU 协议 | MCUmgr 的 SMP(Software Update over MCUmgr Protocol) |
| 适用设备 | 仅 nRF 芯片 + DFU Bootloader | 所有运行 Zephyr RTOS 的设备 |
| 核心依赖 | NordicDFU 库 | iOSMcuManagerLibrary(MCUmgr 客户端) |
| 固件形式 | hex/zip + init 包 | .bin 或带 manifest.json 的 .zip |
关键点:Zephyr DFU 走的是 MCUmgr 的 SMP 协议,即设备端的 MCU Manager 组件负责接收固件分组(Image Group)并校验写入。iOS 端只需要通过 BLE 收发 MCUmgr 帧,协议细节全部由 FirmwareUpgradeManager 封装。
💡 简单记忆:Nordic DFU 管 Nordic 设备,MCUmgr/SMP 管 Zephyr 设备。
快速开始:把 Zephyr 固件文件传到 iPhone
升级前,需要先把编译好的固件文件放进 App 可访问的位置,常用两种方式:
方式一:iTunes / Finder 文件共享(推荐批量操作)
打开 iTunes 的设备页 →「文件共享」→ 选择 nRF Toolbox,把固件拖入右侧列表即可。
方式二:iPhone 的「文件」App(AirDrop / 邮件附件 / iCloud)
固件发到 iPhone 后,在「文件」App 里选择「与 nRF Toolbox 共享」即可。
完整升级流程:三步走完 Zephyr DFU
第 1 步:连接 Zephyr 设备
进入 App 中的 MCU Manager 入口,点击主按钮会打开扫描器,选择你的 Zephyr 设备并连接。
第 2 步:选择固件文件
连接成功后自动进入固件选择页。系统支持两种格式:
.bin:单个固件镜像,直接作为 Image 0 传输;.zip:必须包含manifest.json,描述每个镜像文件名与image_index(支持多核/多 Image 升级)。
解析逻辑集中在 ZephyrFileSelector.swift:FileType 通过 iOS 的 UTI 判断文件是 zip 还是 bin;ZephyrFileManager.extract 解压后读取 manifest.json,把每个镜像按 image_index 存入字典,最终封装成 McuMgrFirmware。
第 3 步:一键启动升级
选中固件后进入升级页。这里通过 McuMgrBleTransport 建立 BLE 传输通道,交给 FirmwareUpgradeManager 启动传输(见 ZephyrDFUTableViewController.swift):
let transport = McuMgrBleTransport(peripheral.peripheral)
manager = FirmwareUpgradeManager(transporter: transport, delegate: self)
try manager?.start(images: firmware.tupleRepresentation)
- 进度:
uploadProgressDidChange回调把已发送字节换算成百分比,驱动顶部进度条(L148-L151); - 状态:
UPDATING → COMPLETED / 错误信息,失败时按钮切换为 Retry / Show Log / Done; - 日志:切到 Logger 标签页,
McuMgrLogObserver按 MCUmgr 日志级别(info / warning / error / verbose…)过滤展示设备回传日志,实现见 McuMgrLogObserver.swift。
源码结构速览:ZephyrDFU 模块怎么组织的
整个模块位于 Profiles/ZephyrDFU/,结构非常清晰:
Profiles/ZephyrDFU/
├── Models/
│ ├── McuMgrFirmware.swift # 固件容器:image_index → 镜像数据
│ └── ZephyrPacket.swift # 升级数据包(对接 NordicDFU 的 DFUPacket)
└── ViewController/
├── ZephyrDFURouter.swift # 路由:设备选择 → 文件选择 → 升级页
├── ZephyrDFUTabBarViewController.swift # 升级页 Tab 容器(进度 + 日志)
└── NotConnectedViewController/
├── FileSelection/ # .bin/.zip 解析与文件选择
├── UpdateScreen/ # 升级进度表格页
└── Util/McuMgrLogObserver.swift # MCUmgr 日志观察器
导航由 ZephyrDFURouter.swift 统一管理:goToPeripheralSelector(连设备)→ goToFileSelector(选固件)→ goToUpdateScreen(开升级),初始状态由 setInitialState 回到 NotConnectedViewController.swift 的「MCU Manager」入口页。
固件数据模型 McuMgrFirmware.swift 极简:就是一个 [Int: Data] 字典——键是 Image 索引,值是镜像字节,这正是 SMP 协议要求的分组形式。
常见问题快查:升级失败怎么办
| 症状 | 可能原因 | 处理 |
|---|---|---|
| 提示「Unsupported file format」 | 文件既不是 bin 也不是 zip | 重新确认固件扩展名,hex 需先转 bin |
| 提示「Archive doesn't contain required files」 | zip 里缺 manifest.json 或字段错误 | 检查 file 与 image_index 字段是否完整 |
| 进度 0% 卡死 | 设备未开启 MCUmgr / SMP,或 BLE 通道未建立 | 确认 Zephyr 侧已启用 MCU Manager 并允许 SMP 命令 |
| 校验失败 | 固件被截断或版本不匹配 | 重传原始固件;查看 Logger 页的详细错误日志 |
| 传输中断 | 设备距离过远、射频干扰 | 靠近设备、关闭 Wi-Fi 重传 |
💡 排障黄金法则:失败后先点 Show Log,Logger 页会给出 MCUmgr 协议的错误码与设备侧日志,80% 的问题都能直接定位。
动手练习:本地跑一遍
git clone https://gitcode.com/gh_mirrors/io/IOS-nRF-Toolbox
用 Xcode 打开 nRF Toolbox.xcodeproj,依赖(iOSMcuManagerLibrary、NordicDFU、ZIPFoundation)已在工程中配置。准备好一块运行了 Zephyr 且启用 MCU Manager 的开发板,按上文三步即可完整体验 Zephyr DFU 的 MCUmgr/SMP 固件传输流程。
小结:Zephyr DFU 模块用不到 10 个 Swift 文件,就完整实现了「设备连接 → 固件解析 → SMP 传输 → 日志排障」的闭环。想深入自研 OTA 功能,从 Profiles/ZephyrDFU/ 入手,是最短的学习路径。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



