L2CAP(Logical Link Control and Adaptation Protocol)中文名为逻辑链路控制和适配协议,它位于BLE协议的主机(Host)部分,承担着协议复用(Protocol Multiplex)的任务。蓝牙协议官方手册的章节首页提到L2CAP还承担上层(ATT,SM)发来的数据的分割/重组(Segmentation/Reassembly)任务。这里需要澄清一点,这个功能仅适用于经典蓝牙协议,在BLE协议范围内,L2CAP层仅仅使用了最精简的一部分,即协议复用(此处小编还有待考证)。BLE的主机部分在L2CAP之上还有ATT(Attribute Protocol)层和SM(Security Manager)层,它们的协议实现和数据格式完全不同,却都可以通过L2CAP层传至协议栈的控制器部分,这就是所谓的协议复用。在阅读L2CAP的资料的时候,谨记L2CAP的复杂功能可能是为经典蓝牙准备,对于BLE而言,L2CAP几乎没什么内容。
信道
L2CAP的基本概念是信道(Signaling Channel)。信道是个抽象概念,表示两个设备某个协议层之间的通道。每个信道分配一个2字节的信道ID——CID(Channel ID),每个信道功用不同,比如CID=0x0004的信道表示属性协议(Attribute Protocol)专用信道。对于BLE协议,L2CAP共有三个信道ID:
- 0x0004 – 属性协议
- 0x0005 – 低功耗信令信道
- 0x0006 – 安全管理协议
其他信道则用于经典蓝牙。协议复用可以理解为,不同的协议走不同的信道,互不干扰。
数据格式与MTU
主机上层的协议通过L2CAP层时,数据包会被封装成L2CAP数据包格式:
该数据格式主要包括:长度、CID和Payload。
BLE协议中,L2CAP支持的最大数据包长度为27,减去长度(2Bytes)和CID(2Bytes),Payload的最大长度为23!
这个23字节有个名字,叫最大传输单元(Maximum Transmission Unit),简称MTU。BLE协议默认的MTU为23字节。
MTU包括三个部分:OP Code(1Byte),Handler(2Byte),Payload,当MTU=23时,实际用户数据长度仅为20字节。在BLE协议规范中,L2CAP抛弃了数据分割和重组的工作,主要原因是在ATT层中,数据长度会被MTU所限制,进而传送到L2CAP的数据一定适用于L2CAP的Payload长度,也就无需额外的分割和重组。所以MTU是一个很关键的参数,两个BLE设备进行数据通信,当个数据包的有效长度不超过(MTU-3)。
在早期的智能手机中,蓝牙的MTU大小设定为固定的23,导致BLE从机设备与之通信,都会将包长度限制在20个字节以内。现在,新版的iOS的默认MTU已经增加到158,Android的MTU也可以进行设定。联想前面链路层里介绍的Payload是27个字节,这里将MTU与之关联起来,如下图所示:
我比较感兴趣的是,GAP层的广播数据,最大可有31个字节,这显然超出了L2CAP的Payload限制,根据一些文档的介绍,原因“好像”是广播数据包的传输,不经过L2CAP层,直接到达链路层,形成广播PDU。相应的参考链接
更新连接参数
L2CAP层有一个著名的功能,即更新BLE的连接参数。
BLE的连接参数包括:
- 最小连接间隔(Min Connection Interval)
- 最大连接间隔(Max Connection Interval)
- 从设备延迟响应(Latency)
- 监控超时(Supervisor Timeout)
这个问题在链路层有过介绍,这里简要重复一下。连接间隔是BLE连接中相邻的两个连接事件(Connection Event)之间的时间间隔。在一个连接事件中,主机发出一个Request,从机回复一个Response。主从之间的数据就是在这些Request和Response之中被传递。如果从设备端数据较长,那么在同一个连接事件中,会有多个Response。相邻的Response之间有一个固定的时间缝隙,称为IFS(Internal Frame Space),它为固定的150us,我们经常能在一些图文说明中见到T_(IFS)就是它。这个参数很重要,可以帮助我们推导出BLE的传输速率的极值。主机可以自由的更改连接参数,如果从机希望更改,则需要向主机发出更新请求,等待主机响应。通常主机都会接受,但是如果从机给出的参数过于苛刻,则主机可能拒绝。从使用角度讲,为了避免拒绝的发生,从机请求的连接参数应该是合理可行的,所以连接间隔设计成了大小值的形式,而非确定值。不过一般情况下,最终的连接间隔就等于最大连接间隔与最小连接间隔的平局值。Android系统的默认连接间隔为7.5ms,而iOS为18.75ms。因此,在不更新连接间隔的情况下,应该能发现iOS的通信速率会相对慢一点。
通信速率
Link Layer中的数据包格式如上图的数据格式与MTU所示。BLE的通信速率为固定的1Mbps,即传输1bit的时间为1μs。那么传输这样一个链路层数据包,取Payload为最大的27字节,所需要的时间为(1 + 4 + 2 + 27 + 4 + 3) * 8 = 328us。
连接事件模型如下:
主机发一个Data,从机响应一下(ACK),响应数据包中,PDU可以为空。那么可以算出当Payload为空时,整个Link Layer数据包传输所需要时间为(1 + 4 + 2 + 0 + 0 + 3) * 8us = 80us。
考虑中间的IFS间隔,那么一对Data-ACK所需要的时间为:328us + 150us + 80us + 150us = 708us。即主从之间完成一次通信握手所需要的最小时间为708us。在理想情况下,通信过程以这个速率进行下去,1秒的传输速率为:1s / 708us * 8bit * 27 Byte = 305bps。305bps(38KB/s) 是BLE通信速率的极限。现实中的BLE通信,肯定达不到这个速率,那瓶颈在哪里呢?
BLE通信是以连接事件为单位的,假如连接间隔为10ms,一次连接事件中共可以进行10ms / 708us = 14次握手。可是,这个14是理论值,实际上达不到,因为BLE通信过程中因为数据传输异常导致的重传是必然发生的,对于iPhone,网上有些资料讲iPhone和Anroid系统中一个连接间隔中仅能实现4次握手。考虑到iPhone的默认连接间隔是18.75ms,Android是7.5ms,那么对iPhone而言,1秒内可以传输的数据总量为1s / 18.75ms * 4 * 27 = 5.76kB/s,Android为:14.4kB/s。
这里计算中用到的27是指链路层的PDU的数据长度,根据前面的数据封包规则,27个字节中,用户数据仅有20个字节,所以上述的数据速率还要乘以一个系数 20/27,那么iPhone的BLE传输速率约为4kB/s,Android约为10.6kB/s。
据我们实际测试,手机与BLE设备进行通信,4kB/s是一个比较现实的测量数据,这个页面提到他们能够达到10kB/s的速率。
所以,与手机进行BLE通信,不要指望太高的通信速率。不过,BLEv4.2协议对此有了改善,通过提高PDU的容量,显著提高最终的通信速率,参考。
当然,BLE设备与设备之间进行通信,则没有那么多限制,至少在单个连接事件中的握手次数限制不会那么苛刻。
MTU与MPS
在PSoC Creator中可以看到这两个选项:
- MTU:Maximum Transmission Unit
- MPS:Maximum PDU Payload Size
在官方手册中对MPS的介绍中有一段注释:如果不涉及拆包和重组,或者在基础的L2CAP模式下,MTU与MPS应该相等。而对于BLE 4.0/4.1,L2CAP就只有基础模式,因此对于不涉及BLE 4.2的应用,只要将二者设置为一致即可。还有兴趣的话,可以参考这个页面。
MTU与ATT_MTU
L2CAP中的MTU就叫MTU,在ATT层中,也有一个MTU,叫ATT_MTU。因为BLE协议中,L2CAP失去了分包重组的功能,因此数据包的大小需要在ATT层限定好,也就需要一个ATT_MTU,这时,只要L2CAP的Payload能够容纳ATT_MTU即可保证通信顺畅。显然,如果ATT_MTU比MTU大,可能引起冲突,因为上层数据包可能超过了L2CAP的Payload容纳极限。在不混淆的情况下,二者可以统称为MTU,并且在非特殊情况下,二者应该设为相同大小。
(完)
原作者:CY大象,原链接已失效,插图大量丢失,小编已重新整理