从core spec v4.2开始,低功耗蓝牙(Bluetooth Low Energy,以下简称BLE)支持链路层数据包PDU长度的管理。链路的两端可以互相协商,通过链路控制过程“Data Length Update Procedure”实现数据包中payload长度的更新,使用更合适的(通常是比默认值更长的)数据包长度。本文简单介绍其基本原理,顺带提供一些数据比对,以及core spec中此部分的变化过程。
Why “Data Length Extension”?
BLE在core spec v4.0中引入,它最本质的特征是省电。为了省电,蓝牙工作组赋予了BLE很多特性,比如类似经典蓝牙sniff mode的数据交互方式,比如长度较短的链路层数据包。最初,BLE链路层数据包(Data Packet)的最大长度为27 octets。随着更多应用场景的引入(比如语音识别等),27 octets的payload长度已经无法再满足所有使用场景。于是,core spec 4.2引入了“Data PDU Length Management”这一章节,支持更新链路层的数据包中payload字段的长度,将最大长度提升至最大251 octets。
我们可以简单对比下最大27 octets和最大251 octets这两种情况下的理论数据速率。考虑物理层速率为1Mbps并且链路加密的情况下,单向最大传输数据速率。这里以master->slave这个方向为例,具体的空中包交互如下图:在上图中,M->S以最大数据包payload传输,而S->M则以空包应答,最小帧间隔T_IFS为150微秒。
对于最大27 octets的情况,payload为27 octets,则PDU长度为27+2(header)+4(MIC)=33 octets。因此整个M->S的数据包长度为:
1(Preamble) + 4(Access Address) + 33(PDU) + 3(CRC) = 41 octets ~ 328us
S->M的数据包长度为:
1(Preamble) + 4(Access Address) + 2(PDU) + 3(CRC) = 10 octets ~ 80us
因此,理论上的最大单向有效(仅payload为有效数据)数据率为:
(27*8) / (328+150+80+150) * 106 = 305kbps
对于最大251 octets的情况,PDU长度为251+2+4=257 octes。整个M->S的数据包长度为:
1(Preamble) + 4(Access Address) + 257(PDU) + 3(CRC) = 265 octets ~ 2120us
理论最大单向数据有效数据率为:
(251*8) / (2120+150+80+150) * 106 = 800kbps
可以看到,支持最大251 octets的情况下,有效数据率得到了很大的提升,甚至可以传输bitpool为53的SBC数据。因此,支持“Data Length Extension”可以显著提高BLE的有效数据率,使其适用于对数据吞吐率要求更高的场景。
What does “Data Length Extension” extends?
如上图,“Data Length Extension Procedure”主要更新了两大类参数:
- 时间参数,指传输整个数据包所需要的时间;
- 长度参数,指数据包PDU中payload字段的长度;
你也许会想,有了payload的字节长度还不够么,为什么还需要数据包的整个时间长度呢?“Octets”不能完全决定“Time”的值么?
答案是:“Octets”类参数并不能完全决定“Time”类参数,因为BLE还有一个特殊的物理层,即core spec 5.0引入的“Coded PHY”。“Coded PHY”会对数据进行前向纠错编码(FEC),因此对于同一个payload字段,在“Coded PHY”传输会比在“Uncoded PHY”上消耗更多的时间。
根据最近这几版core spec的更新情况(从v4.2到v5.0再到v5.1),个人推测在core spec v4.2推出“Data Length Extension”的时候,蓝牙工作组已经提出了“Coded PHY”,只是有些细节还没确定好,所以它没有在4.2中一起正式推出。为了兼容“Coded PHY”,蓝牙工作组先在“Data Length Extension”中预留了“Time”类相关的参数,但不提它究竟有何用(毕竟在1M uncoded phy中,只需要“octets”一类参数就够了);等到5.0推出“Coded PHY”,才解释这里“Time”类参数的用途。
Bunch of Parameter Definitions
翻到core spec v5.1的“Data PDU length management”这一节(Vol 6. Part B. 4.5.10),你会发现它定义了非常多的相关参数。除了前面提到的“Time”类参数和“Octets”类参数,还区分local和remote参数,uncoded PHY和coded PHY参数。这里依据spec的定义,将参数分为下面三类,简单介绍下。
-
Controller Maintained Global Parameters
说是全局的参数,实际是controller的初始化参数(connInitialMax*)以及代表controller收发能力的参数(supportedMax*)。前者目前只有controller自己知道;对于后者,host可以通过“LE Read Maximum Data Length command”来获知。 -
Controller Maintained Parameters for Each Connection
这是对于某一条特定的链路而言,master和slave各自的收发参数,即local参数(connMax*)和remote参数(connRemoteMax*)。值得注意的是,这里的参数都是master和slave各自定义的,而并不是最终这条链路上使用的参数。双方需要经历“Data Length Update Procedure”来协商即将启用的参数。 -
Parameters Derived from the Parameters Maintained by the Controller:
这类参数大多以“connEffectiveMax”字段开头,表明它们才是最终生效的参数。当然,这里面还包含专门为“Coded PHY”定义的参数,因为它确实“不同寻常”。
大体上,链路的双方需要告知各自的收发能力,最后每一端根据自身的能力与对端的能力,决定最终的参数。例如,在决定本地最大的TX字节数时,需要考虑对端的RX能力,不能超过对端最大可接收的直接数。因此,有如下公式计算实际最大TX字节数:
connEffectiveMaxTxOctets = min(connMaxTxOctets, connRemoteMaxRxOctets)
其他参数以此类推。
Why “Data Length Extension” for LE Coded PHY is Different?
考虑是否支持“Data Length Extension”以及是否支持“Coded PHY”这两种情况,最终使用的参数会有如下最小与最大值的限制:
以上唯一需要注意的,是表格右下角的那个值——在同时支持“Data length Extension”和“Coded PHY”的情况下,最大的发包时间。它明显比其他条件下的最大发包时间大很多,甚至比最小的connection interval都要大!它是如何计算得到的呢?我们先看下“Coded PHY”数据包的格式,如下图:
考虑最大payload为251 octets,S=8的情况下,最大TX时间为:
80 + 256 + 16 + 24 + (2+251+4)*8*8 + 24*8 + 3*8 = 17040
由于这个参数和最小connection interval可比,因此在决定实际使用的最大TX/RX时间参数时,需要考虑它们和connection interval的关系。在Core Spec v5.0当中,只考虑了TX与RX的关系,即最大TX时间受到RX时间的限制。它有一个相关的参数connIntervalPortionAvailable,计算方式如下:
connIntervalPortionAvailable = connInterval - ((2*T_IFS) + min (connEffectiveMaxRxTime, ((connEffectiveMaxRxOctets * 64) + 976)))
它表示的,是在极端的情况下,一个connInterval中master和slave各自只发送一个packet,扣除两个最小帧间隔,以及slave可以发送的包的最大时间长度,剩下的就是master的可用发包时间,图示如下:
在这里,它没有考虑到一种普遍的情况,即在“Coded PHY”中,connInterval有可能比slave可以发送的最大数据包的时间长度要小,实际计算得到的connIntervalPortionAvailable 可能是一个负数!到了Core Spec v5.1,这一点得到了修正。Spec提出了“Coded PHY”的最小connection interval的概念——connIntervalCodedMin。这个参数表示的,是在使用1:8的编码情况下(输入1bit,输出8bit),保证最大RX时间,TX只发送最短(27 octets)的数据包,此时的connection interval的值。从master的角度来看,具体如下图所示:
When to Update Data Length?
参数更新的时机,基本都是controller自己决定的。只要“connMaxTxOctets”,“connMaxRxOctets”,“connMaxTxTime”,“connMaxRxTime”不是各自链路的默认最小值(这里Time类参数区分Coded PHY和Uncoded PHY,前者为2704us,后者为328us),controller就可以发起“Data Length Update Procedure”。
对于host端而言,它只知道controller的收发包能力参数(supportedMax×),因此不会自动触发参数更新,虽然有专门的HCI command允许host这样做。在Android平台,google的BT stack会在更新ATT的MTU size之后自动发起“Data Length Update”。Host只在“LE Set Data Length command”中告诉controller它期望的最大“TxOctets”与最大“TxTime”,由controller去和对端协商最终使用的参数。