BLE协议栈结构
- 先看一下BLE协议栈的结构,分成Host和Controller两层
BLE协议栈由控制器Controller和主机Host两大部分组成。任何蓝牙Profile和应用程序的实现都位于协议栈的GAP和GATT层之上。
- PHY(物理层):2.4G无线系统
- LL(链路层):控制设备的RF状态,设备处于五种状态之一
- Standby(准备就绪)
- Advertising(广播)
- Scanning(扫描)
- Initiatng(启动连接)
- Connected(已连接)
- HCI(主机控制接口):通过标准接口提供主机与控制器之间的通信,一般接口有UART、SPI、USB等
- L2CAP(链路逻辑控制和适配协议):向上层提供数据封装服务,允许端到端的数据通信。
- SM(安全管理器):定义了配对和秘钥分发的方法,并为协议栈的其他层提供了与其他设备安全地连接和交换数据的功能
- ATT(属性协议):允许设备向其他设备公开部分数据或属性
- GAP(通用访问协议):与应用程序或Profile直接交互,用于处理设备发现和连接等相关的服务。
- GATT(通用属性协议):定义如何使用ATT的服务框架,BLE中两个设备之间发生的数据通信全部通过GATT,应用程序和Profile直接使用GATT
数据包格式
LL层数据包格式
- 前导码 + 地址 + PDU + CRC
对于连接后的通讯包,PDU的最前面两个字节为header,header的最前两个bit为LLID,蓝牙BLE就是通过LLID来区分LL层数据和L2CAP层数据的
BLE空中包采用小端模式
PDU前两个字节固定为LL Header和PayloadLength
Access Address用来标示接收者ID,根据Access Address不同可分为广播包和数据包
- 广播包Access Address 固定为0x8E89BED6,广播包只能在广播信道channel上传输,即只能在37/38/39信道上传输
- 数据包Access Address为一个32bit的随机值,由Initiator生成。数据包只在数据信道上传输,即除37/38/39之外的其余37信道。每建立一次连接,重新生成一次Access address。数据包是给连接通信使用的,即用于master和slave之间通信的。
广播数据包
Advertising Header即前述的LL header,长度为一个字节
- PDU Type为3bit,具体定义如下。可以看出扫描PDU和发起连接PDU都属于广播包(
CONNECT_REQ也可写作CONNECT_IND
)
- TxAdd/RxAdd,各占1bit,表示随后的Device Address字段代表的蓝牙MAC地址类型,值0代表Public地址,值1代表Random地址
Payload length定义如下所示,所以广播包PDU最长37个字节
Device Address,广播包中的强制字段,俗称蓝牙MAC地址,如果是广播包,则是advertiser的MAC地址;如果是scan包或者连接请求包,则是scanner的MAC地址。蓝牙device address为6个字节,这样Advertising data最长为:37-6 = 31B,这就是广播包数据最长只能31个字节的由来。如前所述,device address分public和random两种,定义如下
Random device address又有三种类型,定义如下所示:
通道数据包
- 空包
- 数据包
Data header,即前述的LL header,在数据包中的定义如下
- LLID(2bits), link layer ID,对LL PDU进行分类:LL data PDU和LL control PDU。也就是说,普通的数据信道空中包包含LL数据包和LL控制包两种,具体定义如下所示。请大家注意分清data channel packet(数据信道空中包)和LL data packet(LL数据包)的区别,如前所示data channel packet包含LL data packet和LL control packet,LL data packet只是data channel packet的一种。在不引起上下文歧义的时候,我们把他们统一称作“数据包”。
- Link layer支持如下control PDU:
- NESN/SN,NESN和SN各占1bit。SN全称为sequence number,表示当前发送的packet编号。NESN,next expected sequence number,用来告知对方下一个期待的packet的编号。Link layer使用SN来告知对方这个packet是新数据包还是重传包,用NESN来告诉对方你之前发我的包已经收到了(相当于ACK的作用),我现在期待下一个新的数据包了,因此BLE没有专门的ACK包,它是通过NESN/SN来实现ACK和重传双重功能的。请参考如下表格,仔细揣摩NESN和SN是如何编码的,以同时完成ACK和重传功能。
我们来分析#3数据包,#3是master发给slave的,那么#3的NESN和SN是如何确定的呢?其实#3的NESN和SN是通过比较#1和#2的NESN/SN的值来确定的,Master把#1传完之后,会把#1包的NESN和SN记录下来,即表格右边的NESNꞌ和SNꞌ。然后Master会拿SNꞌ跟#2的NESN相比,两者不等,说明slave已经收到了#1包,并期待master发一个新的包给它,此时Master会把SNꞌ增1,形成#3包的SN,表示这个数据包是一个新包,然后发出去;两者相等,说明slave没有收到#1包,此时master需要重传。Master还会拿NESNꞌ跟#2的SN相比,两者相等,说明#2包为新包,然后Master会把NESNꞌ增1,形成#3包的NESN发出去,告诉slave我已经收到#2包了并期待你的下一个包;两者不等,说明#2包为重传包。注意:大家可以从上述表格发现一个规律,就是同一方向相邻的两个数据包,他们的NESN和SN与另一个包的NESN和SN是相反的,比如#3 NESN = #1 #NESN ,#3 SN = #1 #SN ,同样#2和#4 各自的NESN和SN是相互相反的。
我们可以用下面的流程图来描述上述过程。
- MD(1bit),more data,用来指示对方我还有数据包要传,请继续打开射频窗口准备接收。比如Nordic nRF51822一个connection interval可以发6个包或者更多的包(也就是说,一个connection event包含多个数据包交互),用的就是MD来实现的。以notify命令为例,设备(Server)notify第一个数据包并将MD置1,Client(比如手机)收到这个notify命令后,就知道Server还有数据包要传,此时手机可以继续发一个空包给设备,以让设备把第二个notify命令发过来,详情如下所示。注:Master为手机(Client),Slave为设备(Server)。
Payload Length or Data Length,BT4.0/4.1定义如下所示,这就是蓝牙4.0/4.1一个包只能传20个字节的根源。
BT4.2之后,Payload length 8 bits全部用来表示长度,这样的话,payload size最大可达251字节(255 – MIC size)。BLE连接建立之后,可以动态更改data length长度(默认为27字节),这个特性叫做Data Length Extension(DLE),DLE是通过Link layer命令:LL_LENGTH_REQ和LL_LENGTH_RSP来实现的。Data length直接跟蓝牙芯片的射频能力有关,像Nordic的nRF51822只支持BT4.1的Data length,就是因为PHY层已经做死了,无法扩展,但Nordic最新的nRF52832和nRF52840,就都支持DLE,即data length最大可到251字节。
L2CAP length,2字节长度,表示后面information payload的长度,information payload最大长度除了受这个L2CAP length字段约束,同时还受MTU的限制。MTU,Maximum Transmission Unit,是ATT层与L2CAP层可以交互的最大数据长度,或者说是Client与Server可以交互的最大长度。
总结一下,蓝牙spec里面定义了2个长度字段:LL data length和L2CAP length,同时ATT层还定义了一个MTU,以限制ATT PDU最大长度。LL data length可以通过LL_LENGTH_REQ和LL_LENGTH_RSP来动态改变,MTU size则可以通过后面要讲到的Exchange MTU Request和Exchange MTU Response来改变,而L2CAP length无法动态改变,也就是说不能超过65535。
L2CAP CID,2字节长度,逻辑通道的ID,BLE使用固定的通道编号,也就是说虽然蓝牙spec里面也允许BLE使用connection oriented channel,但大部分BLE协议栈实现的时候都是使用固定的通道编号,通道编号定义如下所示:
BLE L2CAP Signaling Channel支持的PDU命令只有三个:
- Command reject
- Connection parameter update request,更新连接参数,比如最小连接间隔,最大连接间隔,slave latency等
- Connection parameter update response,接受或者拒绝上面的请求
Security Manager Protocol(SMP)用来实现配对和密钥分发的,SMP支持如下PDU命令:
Attribute Protocol(ATT),就是我们经常用到的应用层,应用数据就跟在ATT命令后面,ATT支持如下命令列表:
至此BLE空中包解析就告一段落了,再往上就是应用层数据解析了,这个就不是空中包的范畴,而是GATT和profile要定义的事情
如下为一个完整的真实的数据包示例,注意:BLE空中包采用小端模式。
- AAAB5D65501E08040004001B130053D550F6
- AA – 前导帧(preamble)
- 0x50655DAB – 访问地址(access address)
- 1E – LL帧头字段(LL header)
- 08 – 有效数据包长度(payload length)
- 04000400 – ATT数据长度,以及L2CAP通道编号
- 1B – notify command
- 0x0013 – 应用数据handle
- 0x53 – 真正要发送的应用数据
- 0xF650D5 – CRC24值
- LL层数据包
其中LLID这两个bit就是用于区分LL层数据和L2CAP层数据的,其每bit定义如下
当LLID为3时,该数据包为LL控制层数据
- L2CAP层数据包
- 当LLID为2时,该数据包为L2CAP层数据包的起始包,起始包后续会有L2CAP层的长度和L2CAP层的channel ID,
- 当LLID为1时,该数据包为L2CAP层数据包的延续包,延续包后续没有L2CAP层的长度和L2CAP层的channel ID,但这种情况只有当MTU的值大于data length时才会出现这样的包,但一般我们不这样用。
- L2CAP层的数据,根据channel ID不同,又分为三种不同的L2CAP指令
- ATT指令:
用于传输应用通信数据
- 信令指令:
用于更新连接间隔和拒绝错误操作码
- SMP指令:
用于配对过程