蓝牙设备通常需要空中升级(OTA)的能力进行固件更新,本规范定义了空中升级(OTA)的基本流程和指令集。
背景信息
本规范基于蓝牙BLE基础规范。
交互流程
为了保证OTA的安全性,在进行设备OTA之前,必须完成安全认证流程。若认证失败则不允许进行OTA。安全认证详情,请参见蓝牙BLE基础规范。
手机与蓝牙设备OTA流程如下。
基础规范使用
- 广播规范
空中升级(OTA)是可选功能,如果蓝牙设备实现了此功能,需要在广播规范的FMSK字段中标示。
- 服务规范
传输过程使用基础规范已定义的Service和Characteristics,采用指令类型区分。手机App发送固件时,采用WriteWithNoRsp Characteristics(0xFED7),用于加快传输速度。同时蓝牙设备收到数据包后,采用Notify Characteristics(0xFED8)对App应答。接收固件过程中,发现数据序号错误的时候,蓝牙设备上报最后一次正确的序号。
- 数据传输规范
数据传输使用基础规范定义的数据格式和规则。
版本格式
固件类型为一个1字节数字,用来区分同一个设备不同类型固件。版本格式为一个4字节数字,如:0x00010302,表示固件版本号为:1.3.2,版本号只允许递增,最大版本号为:99.99.99。版本格式规则如下。
字节序 | 说明 | 取值范围 | 示例 |
---|---|---|---|
0 | 修订号 | 0x00~0x63 | 1.3.2,修订号为0x02 |
1 | 次版本号 | 0x00~0x63 | 1.3.2,次版本号为0x03 |
2 | 主版本号 | 0x00~0x63 | 1.3.2,主版本号为0x01 |
3 | 保留 | 无 | 无 |
升级规则
- 待升级的固件推送到服务端,并填写固件版本信息和升级原因。
- 当服务端确认推送的固件版本比设备端上报的固件版本新时,服务端推送升级通知到手机App。
- 手机App转发升级请求及固件版本信息(仅包含应用版本信息)和固件大小,CRC。
- 蓝牙设备检查固件的应用版本信息,当App下发的应用版本信息比设备运行的固件的应用版本新时,蓝牙设备进入升级模式,否则退出升级模式。
- 协议设计支持固件断点续传能力,参考“交互流程”第12步,蓝牙设备可以回复上次传输固件的中断的位置,手机App会从指定位置续传。断点续传非强制要求能力,可根据情况实现。
- 协议设计支持快速传输模式,即手机App会连续传输TotalFrame(0<TotalFrame<=16)个数据包而不需要对每个数据包等待蓝牙设备的回复,TotalFrame个数据包发送完成后,蓝牙设备才给予回复,然后手机App进行下一轮数据的传输。
- 除了0x2F指令(下发固件分包)不需要加密外,其余指令通过鉴权流程后均需要加密。
OTA指令集
- CMD 0x20:手机查询设备固件版本。
Payload为1字节:固件类型为1字节,默认填0x00。设备端根据固件类型从 0x21 返回对应类型固件的版本号信息。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(1字节) 0x00 0x20 0x00 0x01 0x00 说明 Total Frame & Seq字段值为0x00表示共1帧数据且当前数据为第1帧。 - CMD 0x21: 设备上报设备固件版本。
Payload为5字节:
- 固件类型(1字节):默认填0x00,遇到不支持的固件类型,固件类型上报 0xFF。
- 固件版本号(4字节):例如0x00000002。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(5字节) 0x00 0x21 0x00 0x05 0x00 0x00000002 说明 0x21指令Msg ID要求与0x20指令中数据一致。 - CMD 0x22:手机下发升级请求。
Payload为12字节:
- 固件类型(1字节):默认填0x00
- 固件版本号(4字节):例如0x00000001
- 固件大小(4字节):例如 0x00123456
- CRC16(2字节):采用CRC16_CCITT
- 升级标示符(1个字节):0-全量升级,1-增量升级,2-静默升级。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(12字节) 0x00 0x22 0x00 0x0c 0x00 0x00000001 0x00123456 0x7890 0x00 - CMD 0x23:设备应答升级请求。
Payload(6字节):
- 是否允许升级(1字节): 0-不可以升级,1-允许升级。
- 上次传输字节数(4字节)
- 允许一次循环可传输的包个数(1字节):取值范围0x00~0x0F,表示1~16包。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(6字节) 0x00 0x23 0x00 0x06 0x01 0x00000000 0x0F 说明 0x23指令Msg ID要求与0x22指令中数据一致;如设备支持断点续传,则上次传输的字节上报已经接收到的固件长度。 - CMD 0x24: 设备上报当前已接收的帧序号和接收的数据长度。
Payload(5字节)
- 接收的帧数(1字节):totalFrame 4bit + frameSeq 4bit
- 数据长度(4字节):例如0x00000200。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(5字节) 0x00 0x24 0x00 0x05 0x20 0x00000200 当设备发现有丢帧时,设备端上报最后一次收到正确的帧序和数据长度。手机端重新从丢失的帧开始发送,并且发送完本次循环的剩余帧。
- CMD 0x25:手机通知设备固件下发结束,可以做固件检查。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(1字节) 0x00 0x25 0x00 0x01 0x01 - CMD 0x26:设备收完包后,上报固件检查结果。
固件检查结果(1字节):0-固件检查失败,1-固件检查成功。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(1字节) 0x00 0x26 0x00 0x01 0x01 说明 0x26指令Msg ID要求与0x25指令中数据一致。 - CMD 0x2F:手机下发固件的分包数据。
Header(1字节) CmdType(1字节) Total Frame & Seq(1字节) Length(1字节) Payload(N字节) 0x00 0x2F 0xF0 0x10 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xAA 0xBB 0xCC 0xDD 0xEE 0xFF 固件按规范的数据长度分包,发送16包作为一次循环,Header中帧序号(Msg ID)按照0~15循环。
说明 Total Frame & Seq字段值为0xF0表示共16帧数据且当前数据为第1帧。
OTA数据传输与Characteristic对应关系
指令类型 | 说明 | 传输使用的Characteristic | Characteristics UUID |
---|---|---|---|
0x20 | 查询设备固件版本 | WriteWithNoRsp Characteristics | 0xFED7 |
0x21 | 上报设备固件版本 | Notify Characteristics | 0xFED8 |
0x22 | 下发升级请求 | WriteWithNoRsp Characteristics | 0xFED7 |
0x23 | 应答升级请求 | Notify Characteristics | 0xFED8 |
0x24 | 上报设备最后接收到的帧序号和实际保存的数据长度 | Notify Characteristics | 0xFED8 |
0x25 | 开始进行固件校验 | WriteWithNoRsp Characteristics | 0xFED7 |
0x26 | 上报固件校验结果 | Notify Characteristics | 0xFED8 |
0x2F | 固件分包数据 | WriteWithNoRsp Characteristics | 0xFED7 |
重传周期
在一个重传周期内如果连续出现同一错误,则只需发送一次0x24指令。重传周期的时间计算方式为500ms*TotalFrame;例如每次循环最大允许发送的数据帧数为10,则重传周期为500ms*10=5秒。
异常处理逻辑
- 当设备发现期望接收的数据包seq与当前收到的数据包seq不相同时,设备回复0x24指令,上报最后一次接收到的连续的数据包的seq和已接收的数据总长度;手机APP或天猫精灵在接收到0x24指令后,使用0x2F指令重新下发丢失的数据包,内容与之前的一致(包括Header和Payload);设备在接收到剩余的数据包之后需要回复一次0x24指令;然后手机App或天猫精灵继续传输剩余的固件信息。
- 设备端如果发现接收数据错误,在重传周期内只允许上报一次0x24指令;如果正确接收到期望的数据则不受此规则限制。
- 当设备回复0x24指令之后,如果在重传周期内没有收到期望的数据包,则再次回复0x24指令。
- 当设备端重复发送同一0x24指令超过5次时,则断开连接。
- 当传输的固件末尾最后剩余的数据小于TotalFrame*MTU时,根据实际的拆包个数确定本轮传输的TotalFrame。当设备端发现已经接收到的数据等于固件总长度时,需要直接回复0x24指令。
异常处理小结
设备端在以下情况下需要回复0x24指令。
- 当设备收齐单次循环发送的所有数据包时,需要回复0x24指令。
- 当设备收到与期望的seq不同的数据包时,需要回复0x24指令,当数据错误时每个重传周期内只允许发送1次0x24指令。
- 当设备收齐重发的单次循环发送的所有数据包时,需要回复0x24指令。
- 当设备在一个重传周期内未接收到期望的seq的数据包,需要回复0x24指令。
- 当设备收到完整固件后,需要回复0x24指令。
参考资料
CRC16算法参数模型。
- CRC-16/CCITT-FALSE
- 宽度 16位
- 多项式POLY 0x1021
- 初始值INIT 0xFFFF
- 结果异或值XOROUT 0x0000
- 输入数据反转 REFIN false
- 输出数据反转 REFOUT false