OTA v5 报错与处理
升级页面上出现的每一种报错,都在下面的时序图里标出了发生位置,并在对应的表里写明它是什么意思、该去哪里查。联调时按编号对照即可。
怎么读 App 的报错
每个报错面板都由一行标题和三行说明组成
| 行 | 内容 |
|---|---|
| 标题 | 设备回报的错误以 Device reported <错误码> 开头;App 自己判定的错误直接写出问题,例如 Device did not answer QUERY_V5,不再借用设备错误码 INTERNAL。结果未知以 Upgrade result is not confirmed: 开头。 |
Expected: | 这一步 App 期待设备返回什么。 |
Observed: | 实际看到了什么,包括具体字段值和重连后读到的 DIS 版本。 |
Next: | 下一步该查什么。以 Firmware: 开头的交给固件侧处理。 |
「结果未知」为什么不能直接判成功或失败
协议第 9 章的成功判据要求五项同时满足:同一绑定的设备重新出现、fresh AUTH 成功、DIS 版本等于目标版本、QUERY_V5 返回这次 transfer 的 SUCCESS、没有回滚。少任何一项,App 都不能显示成功。APPLY 发出之后缺了其中一项,设备可能已经升级,也可能没有,这时只能显示结果未知。面板会写明缺的是哪一项。
A2失败D1结果未知A1弹窗C5自动处理,不报错
A 准备与预检
点 Start upgrade 到发出 OFFER_V5 之前,设备状态不会被改动
| 编号 | App 面板标题(原文) | 结果 | 含义与处理 |
|---|---|---|---|
| A1 | (弹窗「升级失败」,不进入升级) | 弹窗 | 弹窗给出四种之一:请先重新连接并认证设备、该设备保存的身份已不匹配,请移除后重新配对、该设备不满足固件升级的前提条件。最后一种在联调中最常见:设备没暴露 Device Information Service(180A),或 DIS 固件版本不是 a.b.c.d 四段格式。 |
| A2 | Device already runs 0.0.1.10 | 失败 | 包的目标版本与设备 DIS 版本相同,没有可装的内容。如果上一次升级显示结果未知,说明设备其实已经启动了这个版本。要再测一次 OTA,发布更高的版本,或打一个带 ALLOW_DOWNGRADE 标志的包。 |
| A3 | Package 0.0.1.9 is older than the device's 0.0.1.10 | 失败 | 发布更高版本;确实要降级时打带 ALLOW_DOWNGRADE 的包。 |
| A4 | Package is built for another product | 失败 | 包头 productIdHash 与设备不一致。检查这台设备选择的发布通道和产品。 |
| A5 | Package header was rejected | 失败 | 重新构建并发布这个包。 |
| A6 | Device did not answer GET_CAPABILITIES | 失败 | 每次等 15 s,共发 3 次都没回。固件:在设备日志里确认收到了请求,并确认应答是从控制特征值发出的。 |
| A7 | Device reply does not match the request | 失败 | Observed 行写明是哪个字段不符(这里是 transactionId)。App 已主动断开。固件:对照请求核对应答字段。 |
| A8 | Device reported <错误码>: … | 失败 | 设备明确拒绝,按错误码查(见文末错误码表)。 |
| A9 | Device capabilities do not meet OTA wire v5 | 失败 | Observed 行写明哪一项不满足,例如 device must advertise only OTA wire v5、device omits required OTA wire v5 features。固件:修正 CAPABILITIES 字段。 |
| A10 | Package is larger than the device can stage | 失败 | Observed 行给出 包大小/maxModulePackage。缩小包,或在分区允许时提高固件的 maxModulePackage。 |
B 传输
OFFER_V5 到收齐全部数据;中断后都能从设备的 durable cursor 续传
| 编号 | App 面板标题(原文) | 结果 | 含义与处理 |
|---|---|---|---|
| B1 | Device did not answer OFFER_V5 | 失败 | 每次等 15 s,共 3 次。固件:确认收到 OFFER_V5 并在控制特征值上应答。 |
| B2 | Device reported <错误码>: OTA v5 offer rejected … | 失败 | 设备在收包前拒绝,常见 VERSION_TOO_OLD、HARDWARE_MISMATCH、PAYLOAD_TOO_LARGE、KEY_ID_UNKNOWN。恢复动作是 RETRY_REQUEST 的(如 STAGING_UNAVAILABLE)App 会按 retryAfterMs 自动重发,最多 3 次。 |
| B3 | Device reply does not match the request | 失败 | transferId、包大小或 requestNonce 不符,Observed 行写明是哪一条。App 已断开;再次开始会从设备的 durable cursor 续传。 |
| B4 | Device returned an invalid cursor | 失败 | Expected / Observed 行给出 receivedOffset、dataPayloadBytes、windowFrames 的允许范围与实际值。固件:核对 OFFER_ACCEPTED_V5 / TRANSFER_STATUS_V5 的 cursor 字段。 |
| B5 | Device reported <错误码>: … | 失败 | 数据阶段收到恢复动作为 STOP、RESTART_TRANSFER、QUERY_ACTIVE 的错误(如 FLASH_WRITE_FAILED、TRANSFER_MISMATCH),按错误码查。 |
| B6 | Device reply does not match the request | 失败 | Observed:window STATUS cursor is not a submitted frame boundary。设备确认的 offset 不是 App 发出的任何一帧的结尾。固件:检查 durable cursor 的推进逻辑。 |
| B7 | Device did not answer QUERY_V5 | 失败 | 每次等 15 s,共 3 次。固件:确认传输中也能应答 QUERY_V5。 |
| B8 | Device cursor stopped advancing | 失败 | 同一 offset 恢复超过 3 次,或累计超过 10 次。Observed 行给出卡住的 offset。固件:查这个 offset 的帧为什么不被接受(CRC、写 flash、流控)。 |
| B9 | Paused transfer was not resumed | 失败 | 传输处于 PAUSED 时,App 重发 matching OFFER_V5,设备必须回 OFFER_ACCEPTED_V5 并带上 cursor。 |
C 校验与应用
设备验签,用户确认后 App 先持久保存 APPLY 意图,再发 APPLY_V5
| 编号 | App 面板标题(原文) | 结果 | 含义与处理 |
|---|---|---|---|
| C1 | Device did not finish verifying the package | 失败 | 设备迟迟不到 READY_TO_APPLY。固件:对比实际验签耗时与上报的 estimatedVerifyApplyMs,并确认校验结束时发出 TRANSFER_STATUS_V5。 |
| C2 | Device reported <错误码>: OTA v5 terminal status … | 失败 | 常见 HASH_MISMATCH、SIGNATURE_INVALID、TRUST_POLICY_CHANGED,按错误码查。 |
| C3 | Device stopped the transfer without an error code | 失败 | 状态为 ERROR 但 lastErrorCode 为 0。固件:进入 ERROR 时写入错误码。 |
| C4 | Device reported <状态> while verifying | 失败 | Expected 行列出这一步允许的状态。固件:按 09 章核对这一步的状态机。 |
| C5 | (不报错,转入阶段 D) | 自动处理 | 无应答或写入结果不明时,APPLY 可能已经执行。App 不重发 APPLY,直接去重连和对账。 |
| C6 | Device reported <错误码>: … | 失败 | 如 APPLY_FAILED、BAD_STATE,按错误码查。 |
| C7 | Device reported <状态> in reply to APPLY_V5 | 失败 | 期待 APPLYING、REBOOT_SCHEDULED 或 SUCCESS。 |
| C8 | REBOOT_SCHEDULED_V5 has an invalid reboot delay | 失败 | 另一条是 …invalid ready time。Expected 行给出允许范围:rebootInMs ≥ 500,expectedReadyMs ≥ rebootInMs(未知时填 0xffffffff)。transferId 或目标版本对不上则显示 Device reply does not match the request。 |
| C9 | Device reported <错误码>: … | 失败 | 按错误码查。 |
D 重启与重连
APPLY 发出之后的报错都是结果未知:设备可能已经升级
| 编号 | App 面板标题(原文) | 结果 | 含义与处理 |
|---|---|---|---|
| D1 | Upgrade result is not confirmed: Device did not come back after reboot | 结果未知 | 截止前一次都没连上。Observed 行带最后一次失败原因。固件:确认设备真的重启了、启动耗时没超过上报的 expectedReadyMs、重启后以 BOUND 标志和相同 discriminator 广播。 |
| D2 | Upgrade result is not confirmed: Device came back but Owner AUTH did not complete | 结果未知 | 固件:查新固件启动后的 AUTH 日志;新镜像可能丢了绑定或 OwnerKey。 |
| D3 | Upgrade result is not confirmed: Reconnected without a fresh Owner AUTH | 结果未知 | 查 App 和设备两边这次重连的 AUTH 日志。 |
| D4 | Upgrade result is not confirmed: Reconnected to a different binding | 结果未知 | 两台已绑定设备的 discriminator 可能相同;升级时只留目标设备在附近。 |
| D5 | Upgrade result is not confirmed: Could not reconnect to the device after APPLY | 结果未知 | Observed 行是具体原因,例如 DIS 固件版本缺失或不是四段格式、保存的身份在升级中被改动。 |
重连截止时间:收到 REBOOT_SCHEDULED_V5 时,从收到起算 expectedReadyMs + max(10 s, expectedReadyMs/2) + 2 s,设备报 ETA 未知时按 60 s 计;没收到时是 APPLY 截止时间再加 120 s。手机中途重启的话,再给一次 120 s 的只读对账窗口。
E 对账
重连并 fresh AUTH 后用 QUERY_V5 读取这次 transfer 的最终状态
| 编号 | App 面板标题(原文) | 结果 | 含义与处理 |
|---|---|---|---|
| E1 | Upgrade result is not confirmed: Device did not answer QUERY_V5 | 结果未知 | Observed 行附带重连后读到的 DIS 版本。固件:新固件启动后必须应答这次 transfer 的 QUERY_V5。 |
| E2 | Device reported TRANSFER_NOT_FOUND: …(附诊断) | 失败 | 恢复动作为 STOP / RESTART_TRANSFER / QUERY_ACTIVE 的错误以失败结束,但面板带诊断,本地仍记为结果未知。最常见的是 TRANSFER_NOT_FOUND:固件需要跨重启保留这次 transfer 的结果,让 QUERY_V5 能返回 SUCCESS(09 章成功判据)。 |
| E3 | Upgrade result is not confirmed: Device answered QUERY_V5 with <错误码> | 结果未知 | 恢复动作为 QUERY_AND_RESUME / REAUTHENTICATE 的错误。按错误码查设备日志。 |
| E4 | Upgrade result is not confirmed: Device reply does not match the request | 结果未知 | Observed 行写明哪个字段不符,并附 DIS 版本。 |
| E5 | Upgrade result is not confirmed: Device reported SUCCESS with error fields set | 结果未知 | 固件:以 SUCCESS 结束时清零 lastError 与 recoveryAction,否则改报 ERROR。 |
| E6 | Upgrade result is not confirmed: Device reported SUCCESS but does not run 0.0.1.10 | 结果未知 | 固件:确认新镜像启动且没有回滚,DIS 报的是正在运行的镜像版本。 |
| E7 | Device reported <错误码>: … | 失败 | 按错误码查。若 ERROR 不带错误码,显示为结果未知:Device stopped the transfer without an error code。 |
| E8 | Upgrade result is not confirmed: Transfer shows CANCELLED after APPLY had started | 结果未知 | 固件:已执行 APPLY 的 transfer 不能回到 CANCELLED;查 APPLY 前后的设备日志。 |
| E9 | Upgrade result is not confirmed: Device was still applying when the recovery window ended | 结果未知 | 固件:对比实际应用和启动耗时与上报的 estimatedVerifyApplyMs、expectedReadyMs。重新打开页面即可再查一次。 |
| E10 | Upgrade result is not confirmed: Device runs 0.0.1.10 but the transfer is still READY_TO_APPLY | 结果未知 | 固件:启动新镜像后,把这次 transfer 记为 SUCCESS,让 QUERY_V5 能报告。 |
| E11 | Upgrade result is not confirmed: Transfer state does not match an upgrade that was applied | 结果未知 | 期待 SUCCESS、ERROR、APPLYING 或 REBOOT_SCHEDULED。按 transferId 查设备日志。 |
重新打开升级页面时
App 先用 DIS 版本处理上次留下的 APPLY 记录
- DIS 已是记录里的目标版本:清掉记录,显示
Firmware is up to date。如果当前面板还是结果未知,会附一行说明设备已按 DIS 运行该版本,但 transfer 本身没有确认。这时不再显示Verify result,因为再跑一次只会得到 A2。 - 窗口已过、版本仍不是目标版本:判定上次 APPLY 没有生效,清掉记录,可以重新升级。
- 窗口内:保留记录。再点开始(结果未知时按钮名为
Verify result)会直接进入阶段 D 和 E 对账,不会重发 APPLY。
设备错误码
面板标题里 Device reported 后面的名称;恢复动作由协议规定
| Code | errorCode | recoveryAction | App 处理 |
|---|---|---|---|
0x01 | BAD_OPCODE | STOP | 失败 |
0x02 | BAD_STATE | QUERY_ACTIVE | 失败 |
0x04 | NOT_AUTHORIZED | REAUTHENTICATE | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x05 | BUSY | QUERY_ACTIVE | 失败 |
0x06 | CONTROL_FRAME_MALFORMED | STOP | 失败 |
0x10 | VERSION_TOO_OLD | STOP | 失败 |
0x11 | HARDWARE_MISMATCH | STOP | 失败 |
0x12 | PAYLOAD_TOO_LARGE | STOP | 失败 |
0x13 | PRODUCT_MISMATCH | STOP | 失败 |
0x17 | PACKAGE_FORMAT_INVALID | STOP | 失败 |
0x18 | STAGING_UNAVAILABLE | RETRY_REQUEST | OFFER 阶段:按 retryAfterMs 重发,最多 3 次 |
0x19 | SIGNATURE_SCHEME_UNSUPPORTED | STOP | 失败 |
0x1A | KEY_ID_UNKNOWN | STOP | 失败 |
0x1B | DATA_FRAME_SIZE_UNSUPPORTED | STOP | 失败 |
0x1C | PRIVILEGED_FLAG_NOT_AUTHORIZED | STOP | 失败 |
0x1D | TRUST_POLICY_CHANGED | STOP | 失败 |
0x1E | SECURITY_VERSION_ROLLBACK | STOP | 失败 |
0x20 | TRANSFER_TIMEOUT | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x21 | CRC_FAIL | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x22 | TRANSFER_MISMATCH | RESTART_TRANSFER | 失败 |
0x23 | DATA_FRAME_MALFORMED | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x24 | DATA_LENGTH_INVALID | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x25 | SEQ_DUPLICATE | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x26 | SEQ_GAP | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x27 | FLASH_WRITE_FAILED | STOP | 失败 |
0x28 | TRANSFER_NOT_FOUND | RESTART_TRANSFER | 失败 |
0x29 | FLOW_CONTROL_VIOLATION | QUERY_AND_RESUME | 传输中:自动 QUERY_V5 续传;对账时:结果未知 |
0x30 | HASH_MISMATCH | STOP | 失败 |
0x31 | SIGNATURE_INVALID | STOP | 失败 |
0x40 | APPLY_FAILED | STOP | 失败 |
0x41 | ROLLBACK | STOP | 失败 |
0xF0 | INTERNAL | STOP | 失败 |
| recoveryAction | 协议含义 |
|---|---|
QUERY_AND_RESUME | 停发数据帧,QUERY_V5 取 durable cursor,再以 matching OFFER_V5 续传 |
RETRY_REQUEST | 等待 retryAfterMs 后重发同一条请求 |
RESTART_TRANSFER | 放弃当前 transferId,以新 transferId 重新 OFFER_V5 |
REAUTHENTICATE | 断开并重新完成 fresh OwnerKey AUTH |
QUERY_ACTIVE | QUERY_V5 读取设备当前活动 transfer 后再决定 |
STOP | 终止本次升级,不得重试 |