深入浅出低功耗蓝牙(BLE)协议栈
首页 > PCB > 深入浅出低功耗蓝牙(BLE)协议栈     2018-08-14 低功耗蓝牙协议栈  

BLE协议栈为甚么要分层?怎样理解BLE“链接”?如果BLE协议只有ATT层没有GATT层会产生甚么?

协议栈框架
一般而言,咱们把某个协议的实现代码称为协议栈(protocol stack),BLE协议栈就是实现低功耗蓝牙协议的代码,理解以及掌握BLE协议是实现BLE协议栈的前提。在深入BLE协议栈各个组成部份以前,咱们先看一下BLE协议栈整体架构。

协议栈框架

 如上图所述,要实现一个BLE应用,首先需要一个支持BLE射频的芯片,然后还需要提供一个与此芯片配套的BLE协议栈,最后在协议栈上开发自己的应用。可以看出BLE协议栈是链接芯片以及应用的桥梁,是实现全部BLE应用的枢纽。那BLE协议栈具体包括哪些功能呢?简单来讲,BLE协议栈主要用来对于你的应用数据进行层层封包,以生成一个知足BLE协议的空中数据包,也就是说,把应用数据包裹在一系列的帧头(header)以及帧尾(tail)中。具体来讲,BLE协议栈主要由以下几部份组成:

PHY层(Physical layer物理层)。PHY层用来指定BLE所用的无线频段,调制解调方式以及法子等。PHY层做得好不好,直接抉择全部BLE芯片的功耗,灵敏度以及selectivity等射频指标。

LL层(Link Layer链路层)。LL层是全部BLE协议栈的核心,也是BLE协议栈的难点以及重点。像Nordic的BLE协议栈能同时支持20个link(链接),就是LL层的功勋。LL层要做的事情非常多,譬如具体选择哪一个射频通道进行通讯,怎样识别空中数据包,具体在哪一个时间点把数据包发送出去,怎样保证数据的完全性,ACK如何接管,如何进行重传,以及如何对于链路进行管理以及控制等等。LL层只负责把数据发出去或收回来,对于数据进行怎么样的解析则交给上面的GAP或ATT。

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协议栈的工作原理,以及每一一层具体干甚么的,为甚么要这么分层。下面我以如何发送一个数据包为例来说解BLE协议栈各层是如何紧密配合,以完成发送任务的。

如何通过无线发送一个数据包
假设有装备A以及装备B,装备A要把自己目前的电量状态83%(十六进制表示为0x53)发给装备B,该怎样做呢?作为一个开发者,他但愿越简单越好,对于他而言,他但愿调用一个简单的API就能完成这件事,譬如send(0x53),实际上咱们的BLE协议栈就是这样设计的,开发者只需调用send(0x53)就能够把数据发送出去了,其余的事情BLE协议栈帮你搞定。得多人会想,BLE协议栈是否直接在物理层就把0x53发出去,就以下图所示:

发送一个数据包

这种方式初看起来挺美的,但由于得多细节没有斟酌到,实际是不可行的。首先,它没有斟酌用哪个射频信道来进行传输,在不更改API的情况下,咱们只能对于协议栈进行分层,为此引入LL层,开发者仍是调用send(0x53),send(0x53)再调用send_LL(0x53,2402M)(注:2402M为信道频率)。这里还有一个问题,装备B怎样知道这个数据包是发给自己的仍是其他人的,为此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)。LL层还要检查数据的完全性,即数据在传输过程当中有无产生窜改,为此引入CRC24对于数据包进行检修 (假设为0xB2C78E) 。同时为了调制解调电路工作更高效,每一一个数据包的最前面会加上1个字节的preamble(前导帧),preamble一般为0x55或0xAA。这样,全部空中包就变为(注:空中包用小端模式表示!):

广播方式

上面这个数据包还有以下问题:

1. 没有对于数据包进行分类组织,装备B没法找到自己想要的数据0x53。为此咱们需要在access address之后加入两个字段:LL header以及长度字节。LL header用来表示数据包的LL类型,长度字节用来指明payload的长度

2. 装备B何时开启射频窗口以接管空中数据包?如上图case1所示,当装备A的数据包在空中传输的时候,装备B把接管窗口关闭,此时通讯将失败;同样对于case2来讲,当装备A没有在空中发送数据包时,装备B把接管窗口打开,此时通讯也将失败。只有case3的情况,通讯才能成功,即装备A的数据包在空中传输时,装备B正好打开射频接管窗口,此时通讯才能成功,换句话说,LL层还必须定义通讯时序。

3.当装备B拿到数据0x53后,该如何解析这个数据呢?它到底表示湿度仍是电量,仍是别的意思?这个就是GAP层要做的工作,GAP层引入了LTV(Length-Type-Value)结构来定义数据,譬如020105,02-长度,01-类型(强制字段,表示广播flag,广播包必须包括该字段),05-值。由于广播包最大只能为31个字节,它能定义的数据类型极为有限,像这里说的电量,GAP就没有定义,因此要通过广播方式把电量数据发出去,只能使用供应商自定义数据类型0xFF,即04FF590053,其中04表示长度,FF表示数据类型(自定义数据),0x0059是供应商ID(自定义数据中的强制字段),0x53就是咱们的数据(装备双方约定0x53就是表示电量,而不是其他意思)。

终究空中传输的数据包将变为:

AAD6BE898E600E3B75AB2A02E102010504FF5900538EC7B2

  • AA – 前导帧(preamble)
  • D6BE898E – 访问地址(access address)
  • 60 – LL帧头字段(LL header)
  • 0E – 有效数据包长度(payload length)
  • 3B75AB2A02E1 – 广播者装备地址(advertiser address)
  • 02010504FF590053 – 广播数据
  • 8EC7B2 – CRC24值
空中传输的数据

有了PHY,LL以及GAP,就能够发送广播包了,但广播包携带的信息极为有限,而且还有以下几大限制:

1. 没法进行一对于一通讯 (广播是一对于多通讯,而且是单方向的通讯)
2. 由于不支持组包以及拆包,因此没法传输大数据
3. 通讯不可靠。广播信道不能太多,否则将致使扫描端效力低下。为此,BLE只使用37(2402MHz) /38(2426MHz) /39(2480MHz)三个信道进行广播以及扫描,因此广播不支持跳频。由于广播是一对于多的,所以广播也没法支持ACK。这些都使广播通讯变得不可靠。
4. 扫描端功耗高。由于扫描端不知道装备端何时广播,也不知道装备端选用哪一个频道进行广播,扫描端只能拉长扫描窗口时间,并同时对于37/38/39三个通道进行扫描,这样功耗就会对比高。
而链接则可以很好解决上述问题,下面咱们就来看看链接是如何将0x53发送出去的。

链接方式
到底甚么叫链接(connection)?像有线UART,很容易理解,就是用线(Rx以及Tx等)把装备A以及装备B相连,即为链接。用“线”把两个装备相连,实际是让2个装备有共同的通讯媒介,并让二者时钟同步起来。蓝牙链接有未尝不是这个道理,所谓装备A以及装备B建立蓝牙链接,就是指装备A以及装备B二者“同步”成功,其具体包括以下几方面:

  • 装备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的数据完全性,所以数据包最后变为:

AAAB5D65501E08040004001B130053D550F6

  • AA – 前导帧(preamble)
  • 0x50655DAB – 访问地址(access address)
  • 1E – LL帧头字段(LL header)
  • 08 – 有效数据包长度(payload length)
  • 04000400 – ATT数据长度,以及L2CAP通道编号
  • 1B – notify co妹妹and
  • 0x0013 – 电量数据handle
  • 0x53 – 真正要发送的电量数据
  • 0xF650D5 – CRC24值
  • 虽然开发者只调用了 send(0x53),但由于低功耗蓝牙协议栈层层打包,最后空中实际传输的数据将变为下图所示的样子,这就既知足了低功耗蓝牙通讯的需求,又让用户API变得简单,可谓一举两得!


上面只是对于BLE协议栈实现原理做了一个简单概述,即便如此,由于都是关于BLE协议栈底层的东西,得多开发者仍是会觉得对比枯燥以及晦涩,而且对于得多开发者来讲,他们也不关切BLE协议栈是如何实现的,他们更关切的是BLE协议栈的使用,即怎样开发一个BLE应用。BLE应用是实打实的东西,不能像上面讲述协议栈同样泛泛而谈,必须结合具体的蓝牙芯片以及蓝牙协议栈来说解,为此后面将以Nordic芯片及协议栈作为范例,来具体讲解如何开发BLE应用,以及如何通过代码去理解BLE协议中定义的一些概念以及术语。

文章来源: https://www.cnblogs.com/iini/p/8969828.html 

 

© Copyright 吾爱微电子 | 琥珀川