原文链接:蓝牙协议分析(7)_BLE连接有关的技术分析
系列索引:蓝牙协议分析(1)_基本概念
蓝牙协议分析(2)_协议架构
蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍
蓝牙协议分析(4)_IPv6 Over BLE介绍
蓝牙协议分析(5)_BLE广播通信相关的技术分析
蓝牙协议分析(6)_BLE地址类型
1. 前言
了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connection)是一个相当消耗资源(power和带宽)的过程。特别是当没有数据传输的时候,所消耗的资源完全被浪费了。因而,对很多蓝牙设备来说(特别是功耗敏感的设备),希望在无数可传的时候,能够断开连接。但是,由于跳频(hopping)以及物理通道(Physical Channel)划分的缘故,经典蓝牙连接建立的速度实在难以忍受(要好几秒)。对那些突发的数据传输来说,几秒钟的连接延迟,简直是灾难。
因此,蓝牙SIG制订BLE规范的时候,充分考虑了这方面的需求,极大的简化了连接的建立过程,使连接速度可以达到毫秒级(最快3.75ms就可以搞定)。与此同时,为了节省功耗,也调整了跳频的策略。至此,相比广播通信而言,BLE面向连接的通信,几乎没有额外的代价。
在“蓝牙协议分析(5)_BLE广播通信相关的技术分析”中,我们对BLE的广播通信有了比较全面的了解,本文将接着分析和面向连接的通信有关的技术,包括连接的建立和断开、BLE跳频(Hopping)技术、Link Layer的应答、重传、流控、等等。
2. 怎样才算是建立了连接?
开始之前,我们先回答一个问题,对通信的双方而言,怎样才算建立了连接呢?
从字面上理解,建立了连接,就是指:
当然,在蓝牙这种资源有限的通信系统中,通道无法独占,退而求其次,分时也Okay。因此,在BLE中建立了连接,是这样定义的:
其中,“约定好的时间段”,是时分的概念。而“到指定的物理Channel上”,是跳频的概念。后面的分析,将会围绕这两个概念进行。
另外,和“蓝牙协议分析(5)_BLE广播通信相关的技术分析”类似,我们也将从Link Layer、HCI、GAP三个层次,分别介绍。
3. Link Layer
3.1 角色的定义
和经典蓝牙一样,协议为处于连接状态的BLE设备,定义了两种Link Layer角色:Master和Slave。Master是连接的发起方(Initiator),可以决定和连接有关的参数(很重要,后面会详细介绍)。Slave是连接的接受方(Advertiser),可以请求(或建议)连接参数,但无法决定。
注1:两个BLE设备之间,只能建立一条连接。
3.2 PDU的定义
和广播通信不同,面向连接的通信使用特定的PDU,称作Data Channel PDU,格式如下(LSB---->MSB):
Header(16 bits) | Payload(Variable size) | MIC(32 bits) |
16bits的Header的格式如下:
LLID(2 bits) | NESN (1bit) | SN(1 bit) | MD(1 bit) | RFU(3 bits) | Length(8 bits) |
Payload是有效数据(SDU,L2CAP的PDU),长度由Header中的Length字段觉得,有效范围是0~255。
3.2.1 LL Data PDU
LL Data PDU有两种:
3.2.2 LL Control PDU
Header中的LLID=11b时,表示这个数据包是用于控制、管理LL连接的LL control PDU。LL control PDU的payload的格式如下:
Opcode(1 octet) | CtrlData(0 ~ 26 octets) |
其中Opcode指示控制&管理packet的类型,包括:
3.3 连接的建立
对BLE来说,连接建立的过程很简单,包括:
master在发出连接请求的时候,需要在CONNECT_REQ PDU的payload中,定义和连接有关的参数。payload的格式如下:
InitA (6 octets) | AdvA (6 octets) | LL Data (22 octets) |
其中InitA和AdvA分别是Master和Slave的蓝牙地址,LL data则包含了所有的连接参数,包括:
AA (4 octets) | CRCInit (3 octets) | WinSize (1 octet) | WinOffset (2 octets) | Interval (2 octets) | Latency (2 octets) | Timeout (2 octets) | ChM (5 octets) | Hop (5 bits) | SCA (3 bits) |
3.4 连接建立后的通信过程
3.3小节提到,当Master发出/Slave收到CONNECT_REQ后,就自动进入连接状态,那双方在收发数据的时间窗口怎么确定呢?可参考下面图片1和图片2:
图片1 BLE连接时序---Master视角
图片2 BLE连接时序---Slave视角
1)从Master的视角看,当它发出CONNECT_REQ后,会在1.25 ms + transmitWindowOffset到1.25ms + transmitWindowOffset + transmitWindowSize之间,发送第一个packet(M->S)。同理,Slave在收到CONNECT_REQ之后,也会在相应的时间区间去接收packet(M->S)。
2)Master发出第一个packet之后,将以此为起始点(称作anchor point),以connInterval为周期,接着发送后续的packet(M->S),以及接收Slave的packet(S->M),具体可参考上面图片1。
3)Slave如果没有收到第一个packet(M->S),则会以1.25 ms + transmitWindowOffset为起点,等待connInterval之后,再次尝试接收,直到接收到为止。Slave接收到packet之后,则以收到该packet的时间点为起始点(anchor point),以connInterval为周期,接着接收后续的packet(M->S),以及发送packet给Master(S->M),具体可参考上面图片2。
注2,关于数据传输的速率:
由上面的通信过程可知,BLE面向连接的通信速率,是由connInterval以及每个Connection Event中所传输的数据量决定的。
由上面3.2的描述可知,LL Data PDU的有效负荷不能超过255(251)bytes,不过考虑到一次传输的效率、错误处理等因素,具体的Link Layer不会使用这么大的packet。相应地,为了提高传输速度,一般会在一个Connection Event中,传输多个packet。以iOS为例,它可能会在一个Connection Event中,传输6个packets,每个packet的长度是20bytes。
另外,很多平台为了保证自身作为Master的性能,会限制connInterval的最小值,以iOS为例,最小值是30ms。因此,可估算得到相应的传输速率为20B * 6 / 30ms = 32kbps,是相当缓慢的。
注3:BLE的面向连接通信是使用跳频技术的,即每次Connection Event,都会使用不同Physical Channel收发数据,具体的跳频机制,可参考3.6小节的介绍。
3.5 连接的控制与管理
连接建立之后,Master或者Slave可以借助Link Layer Control Protocol (LLCP),通过LL Control PDU,对连接进行管理控制,包括:
3.6 连接超时及断开
BLE连接断开的原因有两种:一种是预期内的、主动断开,此时会走3.4小节提到的Termination Procedure过程;第二种是一些非预期的原因导致的超时断开,如距离超出、遭受严重的干扰、突然断电等。
对于第一种,是协议内的正常流程,没有什么好说的。而对于第二种,则需要一些timeout机制,检测这写异常情况,具体如下。
注4:connSlaveLatency是一个非常有用的参数,它允许Slave在数据通信不频繁的时候,忽略掉一些Connection Event,进而可以睡得更久,更加省电。
3.7 跳频(Hopping)策略
BLE的跳频策略是非常简单的,即:每一个Connection Event,更换一次Physical Channel,当然,master和slave需要按照相同的约定更换,不然就无法通信。这个约定如下:
图片3 BLE跳频策略
首先,使用一个Basic的算法,利用lastUnmappedChannel和hopIncrement,计算出unmappedChannel。
计算出unmappedChannel之后,查找当前的Channel map,检查unmappedChannel所代表的Channel是否为used channel。如果是,恭喜,找到了。
如果不是,将所有的used Channel以升序的方式见一个表,表的长度是numUsedChannels,用unmappedChannel和numUsedChannels做模运算,得到一个index,从按照该index,从表中取出对应的channel即可。
3.8 应答(Acknowledgement)和流控(Flow Control)
由3.2小节的描述可知,LL Data PDU的Header中,有NESN(Next Expected Sequence Number)和SN(Sequence Number)两个标记,利用它们,可以很轻松的在Link Layer实现应答、重传、流控等机制。
为了实现这些功能,Link Layer会为每个连接创建两个变量,transmitSeqNum和nextExpectedSeqNum(为了和packet的SN/NESN bit区分,我们将它们简称为sn和nesn),并在连接建立的时候,它们都被初始化为0。
Link Layer在收发packet时,会遵循如下的原则(可结合下面图片4理解):
注5:下面图片4是从“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”中截的一张图,不过spec中画的有问题,我用红色字体改正了。另外,这个图片非常有歧义、难以理解,我会在下面解释。
1)无论是Master还是Slave,发送packet的时候,都会将当前的sn和nesn copy到packet的SN和NESN bit中。
2)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的NESN bit和本地的sn比较:如果相同,说明该packet是对端设备发来的NAK packet(请求重发),则需要将旧的packet重新发送出去;如果不同,说明是对端设备发来的ACK packet(数据被正确接收),则需要将本地的sn加1,接着发送新的packet。
3)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的SN bit和本地的nesn比较:如果相同,则说明是一个新的packet,接收即可,同时将本地的nesn加1;如果不同,则说明是一个旧的packet,什么都不需要处理。
4)上面2)和3)两个步骤,是相互独立的,因此一个NAK packet,也可能携带新的数据,反之亦然。
5)当一个设备无法接收新的packet的时候(例如RX buffer已满),它可以采取不增加nesn的方式,发送NAK packet。对端设备收到该类型的packet之后,会发送旧的packet(图片4左边部分的“TX old data, sn”分支)。该设备收到这样旧的packet的时候,不会做任何处理(图片4右边部分的“Ignore RX data”分支)。这就是Link Layer的流控机制(Flow control)
图片4 BLE应答和流控机制
4. HCI
HCI(Host Control Interface)的功能就简单多了,就是要封装Link Layer所提供的功能,包括两类。
1)连接的建立、关闭、参数设置、管理等,这一类是通过HCI command/event(其格式可参考“蓝牙协议分析(6)_BLE地址类型”中的介绍)完成的,包括:
有关这些命令的具体描述,可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 2, Part E] Host Controller Interface Functional Specification”。
2)对ACL data的封装和转发,不再详细说明。
6. GAP
GAP(Generic Access Profile)的主要功能,是定义BLE设备所具备的能力,以实现互联互通的功能。
对BEL基于连接的通信来说,GAP定义了4种连接有关的模式(不同的产品形态,可以选择是否支持这些模式,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] 9.3 CONNECTION MODES AND PROCEDURES”):
相应地,GAP定义了5中和这些模式有关的过程(不同的产品形态,可以选择是否支持这些过程):
这些mode和procedure的具体描述,可参考蓝牙spec[1]。
7. 参考文档
[1] Core_v4.2.pdf