BLE协议栈主要由如下几部分组成:
PHY层(Physical layer物理层)
PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。PHY层做得好不好,直接决定整个BLE芯片的功耗,灵敏度以及selectivity等射频指标。
LL层(Link Layer链路层)。
LL层是整个BLE协议栈的核心,也是BLE协议栈的难点和重点。像Nordic的BLE协议栈能同时支持20个link(连接),就是LL层的功劳。
LL层要做的事情非常多,比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,以及如何对链路进行管理和控制等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者GATT。
HCI(Host controller interface)
HCI是可选的(具体请参考文章:三种蓝牙架构实现方案(蓝牙协议栈方案)),HCI主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通信协议和通信命令等。
GAP层(Generic access profile)
GAP是对LL层payload(有效数据包)如何进行解析的两种方式中的一种,而且是最简单的那一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等。
L2CAP层(Logic link control and adaptation protocol)
L2CAP对LL进行了一次简单封装,LL只关心传输的数据本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。
SMP(Secure manager protocol)
SMP用来管理BLE连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。
ATT(Attribute protocol)。
简单来说,ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是ATT。BLE引入了attribute概念,用来描述一条一条的数据。Attribute除了定义数据,同时定义该数据可以使用的ATT命令,因此这一层被称为ATT层。
GATT(Generic attribute profile)
GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理。没有GATT,BLE协议栈也能跑,但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profile,BLE摆脱了ZigBee等无线协议的兼容性困境,成了出货量最大的2.4G无线通信产品
BLE引入access address概念,用来指明接收者身份
0x8E89BED6这个access address比较特殊,它表示要发给周边所有设备,即广播。
如果你要一对一的进行通信(BLE协议将其称为连接),即设备A的数据包只能设备B接收,同样设备B 的数据包只能设备A接收,那么就必须生成一个独特的随机access address以标识设备A和设备B两者之间的连接。
广播情况
设备A叫advertiser(广播者),设备B叫scanner或者observer(扫描者)。广播状态下设备A的LL层API将变成send_LL(0x53,2402M, 0x8E89BED6)。
由于设备B可以同时接收到很多设备的广播,因此数据包还必须包含设备A的 device address(0xE1022AAB753B)以确认该广播包来自设备A,为此send_LL参数需要变成(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)。
设备A和设备B建立蓝牙连接
指设备A和设备B两者一对一“同步”成功,其具体包含以下几方面:
设备A和设备B对接下来要使用的物理信道达成一致
设备A和设备B双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点
设备A和设备B两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包
设备A和设备B通信流程
设备A称为Master或者Central,把设备B 称为 Slave或者 Peripheral
设备A将周期性以CI(connection interval)为间隔向设备B发送数据包,而设备B也周期性地以CI为间隔打开射频接收窗口以接收设备A的数据包
同时按照蓝牙spec要求,设备B 收到设备A数据包150us后,设备B切换到发送状态,把自己的数据发给设备A
设备A则切换到接收状态,接收设备B发过来的数据。
由此可见,连接状态下,设备A和设备B的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率。
连接状态下是如何把数据 0x53发送出去的
对开发者来说,很简单,他只需要调用send(0x53)
- GATT层定义数据的类型和分组,方便起见,我们用0x0013表示电量这种数据类型,这样GATT层把数据打包成130053(小端模式!)
- ATT层用来选择具体的通信命令,比如读/写/notify/indicate等,这里选择notify命令0x1B,这样数据包变成了:1B130053
- L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053
- LL层要做的工作很多
首先LL层需要指定用哪个物理信道进行传输(物理信道不体现在数据包中)
然后再给此连接分配一个Access address(0x50655DAB)以标识此连接只为设备A 和设备B 直连服务,然后加上LL header和payload length字段,LL header标识此packet为数据packet,而不是control packet等,payload length为整个L2CAP字段的长度,
加上CRC24字段,以保证整个packet的数据完整性,所以数据包最后变成:
o AAAB5D65501E08040004001B130053D550F6
o AA – 前导帧(preamble)
o 0x50655DAB – 访问地址(access address)
o 1E – LL帧头字段(LL header)
o 08 – 有效数据包长度(payload length)
o 04000400 – ATT数据长度,以及L2CAP通道编号
o 1B – notify command
o 0x0013 – 电量数据handle
o 0x53 – 真正要发送的电量数据
o 0xF650D5 – CRC24值
虽然开发者只调用了 send(0x53),但由于低功耗蓝牙协议栈层层打包,最后空中实际传输的数据将变成下图所示的模样,这就既满足了低功耗蓝牙通信的需求,又让用户API变得简单,可谓一箭双雕!
网友评论