wahahahehehe

Tips:

1. 博客内容主要为博主的学习笔记,引用已表明出处,如有侵犯请联系我删除;

2. 如有错误请指出,万分感谢;

3. 博主邮箱:yukai_tao@163.com。

低功耗蓝牙(BLE)协议栈分析

浅析低功耗蓝牙(BLE)协议栈

1、 什么是BLE协议栈?

BLE协议栈就是低功耗蓝牙协议的代码实现,其主要组成部分如下:

Controller 控制器层 PHY (Physical Layer):基带物理层
LL (Link Layer):链路层
HCI (Host controller interface):主机控制接口
Host 主机层 L2CAP (Logic link control and adaptation protocol):逻辑链路控制和适配协议
ATT (Attribute protocol):属性协议
GATT (Generic attribute profile):属性协议配置规范
SMP (Secure manager protocol):安全管理
GAP (Generic access profile):通用访问规范

在蓝牙芯片上实现一个蓝牙应用,首先需要提供与此芯片配套的BEL协议栈(protocol stack),然后在此协议栈的基础上完成应用开发。

2、 BLE协议栈框架

BLE协议栈基本框架如下:

image

可以看出BLE协议栈是连接芯片和应用的桥梁,是实现整个BLE应用的关键。BLE协议栈主要用来对应用数据进行层层封包,以生成一个满足BLE协议的空中数据包,也就是说,把应用数据包裹在一系列的帧头(header)和帧尾(tail)中。

3、 BLE协议栈分层

3.1 PHY层(Physical Layer物理层)

PHY层用来指定BLE所用的无线频段(2.4GHz),调制解调方式(GFSK高斯频移键控),发送功率等。PHY层做的好不好将直接决定该BLE芯片的功耗、灵敏度等等射频指标。

LL层是整个BLE协议栈的核心,LL层定义了两个设备如何利用无线电传输信息,包含了报文、广播、数据通道的详细定义,也规定了发现其他设备的流程、广播的数据、连接建立、连接管理以及连接中的数据传输。比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,以及如何对链路进行管理和控制等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者GATT。

3.2.1 链路层状态机定义了五种状态:

  • 就绪态(Standby):准备状态,不传输或接受数据包

  • 广播态(Advertising):发送广播数据,回应scanner的响应

  • 扫描态(Scanning):监听/扫描,监听广播包,(主动扫描、被动扫描)

  • 发起态(Initiating):初始化,监听来自特殊设备的广播包,并进行初始化连接

  • 连接态(Connection):连接状态,主机角色(从initiator进入)/从机角色(从advertiser进入)

image

3.2.2 状态转移过程

  • 对于主机而言:standby -> scanning -> initiating -> connection/master
  • 对于设备而言:standby -> advertising -> connection/slave
  • 对于scanning状态,主要用于如下场景:当一个设备在收到advertise消息后,如要获取更多关于改advertise的消息,会进入scanning状态

image

3.3 HCI(Host controller interface,主机控制接口)

HCI是可选的,主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通信协议和通信命令等。

L2CAP对LL层进行了一次简单封装,LL只关心传输数据的本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。

(1)信道,L2CAP的基本概念是信道(Signaling Channel)。信道是个抽象概念,表示两个设备某个协议层之间的通道。每个信道分配一个2字节的信道ID-CID(Channel ID),每个信道功用不同,对于BLE协议,L2CAP共有三个信道ID:

  • 0x0004 – 属性协议
  • 0x0005 – 低功耗信令信道
  • 0x0006 – 安全管理协议

其他信道则用于经典蓝牙。协议复用可以理解为不同的协议走不同的信道,互不干扰。

(2)数据格式与MTU

(3)更新连接参数

  • 最小连接间隔(Min Connection Interval)

  • 最大连接间隔(Max Connection Interval)

  • 从设备延迟响应(Latency)

  • 监控超时(Supervisor Timeout)

3.5 ATT(Attribute protocol,属性协议)

ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是ATT。BLE的数据存储在属性服务器的“属性”里,供属性客户端执行读写操作,客户端将请求发送至服务器,服务器回复响应。BLE引入了attribute概念,用来描述一条一条的数据Attribute除了定义数据,同时定义该数据可以使用的ATT命令,及ATT PDU(Protocol Data Unit,协议数据交互单元),分为4类:读(Read)、写(write)、通知(notify)、指示(indicate)。

属性协议定义了六种类型的信息:

  1. 从客户端发送至服务器的请求
  2. 从服务器发送至客户端的回复请求的响应
  3. 从客户端发送至服务器的无需响应的命令
  4. 从服务器发送至客户端的无需确认的通知
  5. 从服务器发送至客户端的指示
  6. 从客户端发送至服务器的回复指示的确认

3.6 GATT(Generic attribute profile,属性协议配置规范)

GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理。没有GATT,BLE协议栈也能跑,但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profile,BLE摆脱了ZigBee等无线协议的兼容性困境,成了出货量最大的2.4G无线通信产品。

3.7 SMP (Secure manager protocol,安全管理)

SMP用来管理BLE连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。

3.8 GAP(Generic access profile,通用访问规范)

GAP是对LL层payload(有效数据包)进行解析的两种方式中的一种,而且是最简单的那一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等。

4、 协议栈在数据无线发送中的作用?

其实协议栈的主要作用就是将用户发送的数据打包成低功耗蓝牙数据包的格式发送出去,并将接收的数据按照低功耗蓝牙数据包的格式解析出来。

假设有设备A和设备B,设备A需要把自己的当前的电量状态83%(0x53)发送给B。

作为BLE应用开发人员,理想状态是调用API send(0x53)即可,剩下的交给蓝牙协议栈。

image

4.1 广播模式

(1) GAP层

​ 引入LTV(Length-Type-Value)结构来定义数据,比如020104,02-长度,01-类型(强制字段,表示广播flag,广播包必须包含该字段),04-值。发送的电量数据0x53通过GAP层封装成04FFD70753,其中0xFF表示数据类型(自定义类型),0x07D7是供应商ID(自定义数据中的强制字段)。

  • 加上广播必须的字段,经过GAP层的封装,数据包变成:02010404FFD70753

(2)LL层

  • 在数据前加上设备A的地址0x84C2E43C3886,为了告诉其他设备,这组数据是由设备A发出的,
    数据包变成: 86383CE4C28402010404FFD70753

  • 此时为了设备B能够找到电量数据0x3C,增加LL header和长度字节,
    数据包变成: 020E86383CE4C28402010404FFD70753

  • 为了确保数据的完整性,增加CRC24校验,
    数据包变成: 020E86383CE4C28402010404FFD70753CAA024

  • 此刻的数据发出去,设备B并不知道这个数据是发给自己的,为此引入access address概念,用来指明接收者身份。0x8E89BED6表示发送给周围所有设备,即广播,连接时会随机生成一组地址。
    D6BE898E020E86383CE4C28402010404FFD70753CAA024

  • 最后加上前导包0xAA,完成的数据包为
    AAD6BE898E020E86383CE4C28402010404FFD70753CAA024

    • AA – 前导帧(preamble)
    • D6BE898E – 访问地址(access address)
    • 60 – LL帧头字段(LL header)
    • 0E – 有效数据包长度(payload length)
    • 86383CE4C284 – 广播者设备地址(advertiser address)
    • 02010404FFD70753广播数据
    • CAA024 – CRC24值

有了PHY,LL和GAP,就可以发送广播包了,但广播包携带的信息极其有限,而且还有如下几大限制:

  1. 无法进行一对一双向通信 (广播是一对多通信,而且是单方向的通信)
  2. 由于不支持组包和拆包,因此无法传输大数据
  3. 通信不可靠及效率低下。广播信道不能太多,否则将导致扫描端效率低下。为此,BLE只使用37(2402MHz) /38(2426MHz) /39(2480MHz)三个信道进行广播和扫描,因此广播不支持跳频。由于广播是一对多的,所以广播也无法支持ACK。这些都使广播通信变得不可靠。
  4. 扫描端功耗高。由于扫描端不知道设备端何时广播,也不知道设备端选用哪个频道进行广播,扫描端只能拉长扫描窗口时间,并同时对37/38/39三个通道进行扫描,这样功耗就会比较高。

而连接则可以很好解决上述问题,下面我们就来看看连接是如何将0x53发送出去的。

4.2 连接模式

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

  • 设备A和设备B对接下来要使用的物理信道达成一致
  • 设备A和设备B双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点
  • 设备A和设备B两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包
  • 连接成功后,设备A和设备B通信流程如下所示:

image

如上图所示,一旦设备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的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率。

对开发者来说,很简单,他只需要调用send(0x53)

  • GATT层定义数据的类型和分组,用0x0013表示电量这种数据类型,这样GATT层把数据打包成130053

  • ATT层用来选择具体的通信命令,比如读/写/notify/indicate等,选择notify命令0x1B,这样数据包变成了:1B130053

  • L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053

  • LL层分配一个Access address(0x50655DAB)以标识此连接只为设备A和设备B直连服务,然后加上LL header和payload length字段和最后加上CRC24字段,数据包最后变成:

    55AB5D65501E08040004001B130053D550F6

    • 55 – 前导帧(preamble)
    • 0x50655DAB – 访问地址(access address)
    • 1E – LL帧头字段(LL header)
    • 08 – 有效数据包长度(payload length)
    • 00040004 – ATT数据长度,以及L2CAP通道编号
    • 1B – notify command
    • 0x0013 – 电量数据handle
    • 0x53 – 真正要发送的电量数据
    • 0xF650D5 – CRC24值

参考链接:

posted on 2021-06-04 20:26  Wahahahehehe  阅读(2042)  评论(0编辑  收藏  举报

导航