文档目标

蓝牙设备通常需要空中升级(OTA)的能力进行固件更新,本规范定义了空中升级(OTA)的基本流程和指令集。本规范基于《蓝牙设备GATT规范》实现。

交互流程

为了保证OTA的的安全性,在进行设备OTA之前,必须完成安全认证流程。若认证失败则不允许进行OTA。安全认证详情参考《蓝牙设备GATT规范》

蓝牙BLE OTA规范 - 图1

基础规范使用

广播规范

空中升级(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 保留

升级规则

1、升级用固件推送到服务端,并填写固件版本信息和升级原因。
2、当服务端确认推送的固件版本比设备端上报的固件版本新时,服务端推送升级通知到手机App。
3、手机App转发升级请求及固件版本信息(仅包含应用版本信息)和固件大小,CRC。
4、蓝牙设备检查固件的应用版本信息,当App下发的应用版本信息比设备运行的固件的应用版本新时,蓝牙设备进入升级模式,否则退出升级模式。
5、协议设计支持固件断点续传能力,参考“交互流程”第12步,蓝牙设备可以回复上次传输固件的中断的位置,手机App会从指定位置续传。断点续传非强制要求能力,可根据情况实现。
6、协议设计支持快速传输模式,即手机App会连续传输TotalFrame(07、除了0x2F指令(下发固件分包)不需要加密外,其余指令通过鉴权流程后均需要加密。

指令集

1、0x20:手机查询设备固件版本

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(1 Byte)
0x00 0x20 0x00 0x01 0x00

固件类型为1字节,默认填0x00。设备端根据固件类型从 0x21 返回对应类型固件的版本号信息。

2、0x21:设备上报设备固件版本,版本为0x00000002

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(5 Byte)
0x00 0x21 0x00 0x05 0x00 0x00000002

固件类型为1字节,默认填0x00。遇到不支持的固件类型,固件类型上报 0xFF。固件版本号为4字节。

3、0x22:手机下发升级请求,升级请求包含五个字段,分别为:固件类型、固件版本号、固件大小、CRC16、升级标示符。

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(12 Byte)
0x00 0x22 0x00 0x0C 0x00
0x00000001 0x00123456
0x7890
0x00

固件类型、固件版本号、固件大小、CRC16、升级标示符按照顺序拼接下发。固件类型为1个字节,固件版本号为4个字节,固件大小为4个字节,CRC16为2个字节,升级标示符为1个字节。CRC16算法采用CRC16_CCITT(参考资料 1)。升级标示符含义,0:全量升级 1:增量升级,默认设为0。

4、0x23:设备应答升级请求,1:允许升级 0:不可以升级。

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(5 Byte)
0x00 0x23 0x00 0x06 0x01
0x00000000
0x0F

是否允许升级(1字节)+ 上次传输字节数(4字节)+ 允许一次循环可传输的包个数(1字节,0x00~0x0f,表示1~16包)

5、0x24:设备上报当前已接收的帧序号和接收的数据长度

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(5 Byte)
0x00 0x24 0x00 0x05 0x20
0x00000200

注:PayLoad 由接收的帧数和接收数据长度组成,帧数1字节(totalFrame 4bit + frameSeq 4bit),数据长度4字节。当设备发现有丢帧时,设备端上报最后一次收到正确的帧序和数据长度。手机端重新从丢失的帧开始发送,并且发送完本次循环的剩余帧。

6、0x25:手机通知设备固件下发结束,可以做固件检查

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(1 Byte)
0x00 0x25 0x00 0x01 0x01

7、0x26:设备收完包后,上报固件检查结果; 1:固件检查成功;0:固件检查失败

Header(1Byte) CmdType(1 Byte) FrameDesc(2 Byte) PayLoad(1 Byte)
0x00 0x26 0x00 0x00 0x01

9、0x2F:手机下发固件的分包数据

Header(1Byte) CmdType(1Byte) FrameDesc(2 Byte) FwData(N Byte)
0x00 0x2F 0xF0 0x10 0x1234…

注:固件按规范的数据长度分包,发送16包作为一次循环,Header中帧序号按照0~15循环。

异常处理

重传周期

在一个重传周期内如果连续出现同一错误,则只需发送一次0x24指令。重传周期的时间计算方式为500msTotalFrame;例如每次循环最大允许发送的数据帧数为10,则重传周期为500ms10=5秒。

设备端收包异常处理逻辑

  • 当设备发现期望接收的数据包seq与当前收到的数据包seq不相同时,设备回复0x24指令,上报最后一次接收到的连续的数据包的seq和已接收的数据总长度;手机APP或天猫精灵在接收到0x24指令后,使用0x2F指令重新下发丢失的数据包,内容与之前的一致(包括Header和Payload);设备在接收到剩余的数据包之后需要回复一次0x24指令;然后手机APP或天猫精灵继续传输剩余的固件信息。

OTA_1.pngOTA_2.png

  • 设备端如果发现接收数据错误,在重传周期内只允许上报一次0x24指令;如果正确接收到期望的数据则不受此规则限制。

OTA_3.png

  • 当设备回复0x24指令之后,如果在重传周期内没有收到期望的数据包,则再次回复0x24指令。

OTA_4.png

  • 当设备端重复发送同一0x24指令超过5次时,则断开连接。

OTA_5.png

  • 当传输的固件末尾最后剩余的数据小于TotalFrame*MTU时,根据实际的拆包个数确定本轮传输的TotalFrame。当设备端发现已经接收到的数据等于固件总长度时,需要直接回复0x24指令。

    异常处理小结

    设备端在以下情况下需要回复0x24指令:

  • 当设备收齐单次循环发送的所有数据包时,需要回复0x24指令

  • 当设备收到与期望的seq不同的数据包时,需要回复0x24指令,当数据错误时每个重传周期内只允许发送1次0x24指令
  • 当设备收齐重发的单次循环发送的所有数据包时,需要回复0x24指令
  • 当设备在一个重传周期内未接收到期望的seq的数据包,需要回复0x24指令
  • 当设备收到完整固件后,需要回复0x24指令

    参考资料

  1. CRC16算法参数模型:CRC-16/CCITT-FALSE、宽度 16、多项式POLY 0x1021、初始值INIT 0xFFFF、结果异或值XOROUT 0x0000、输入数据反转 REFIN false、输出数据反转 REFOUT false。