nimble 蓝牙开发一:概述
一、BLE 简介
蓝牙技术是短距离的无线通信技术,工作在 2.4 GHz 的 ISM 频段上。
按照蓝牙规范的划分,存在两种蓝牙:
- 经典蓝牙(BR/EDR),传输数据量大,功率消耗高;
- 低功耗蓝牙(BLE)。
为了发扬蓝牙在短距离物联方面的优势,SIG (蓝牙兴趣小组)在蓝牙规范 v4.0 中引入了 BLE,定义了 BLE 的架构,以及协议框架。
本文介绍 nimble 蓝牙协议栈的应用开发方法,nimble 只用于 BLE 开发。
二、BLE 基础知识
蓝牙设备地址
在蓝牙规范中,同时存在两种类型的地址:
- 公共地址,由 IEEE 分配,并保证地址的唯一性;
- 随机地址,自定义的地址。
这两种地址在设备中可以同时存在,数据传输时,任一选择使用哪种地址。
BLE 广播类型
在 BLE 中存在广播报文,且广播报文常用如下4种类型:
其中,名词解释如下:
名词 | 解释 |
---|---|
可连接 | 表示接收该广播的设备,可以向发送该广播的设备发送连接请求 |
可扫描 | 表示接收该广播的设备,可以向发送该广播的设备发送扫描请求 |
定向 | 表示在广播帧种指定了该广播的目的蓝牙地址,其他非目的地址的蓝牙设备不会接收到该广播 |
标准广播数据
蓝牙规范 5.2 的 Vol 3, Part C,第 11节中,定义了标准的、符合规范的 BLE 广播数据,其数据结构如下:
如上图所示,广播数据是由一个一个的 AD Structure 组合而成的,而 AD Structure 的结构如下:
其中:
位域 | 描述 |
---|---|
Length | 1 字节 ,包含了 AD Type 位域和 AD Data 位域的长度,不包含 Length 本身的字节长度 |
AD Type | 1 字节,指示当前 AD Structure 中保存的数据类型 |
AD Data | n 字节,具体数据格式由 AD Type 决定,用于保存应用层设置的数据,n + 1 = Length |
关于 AD Type 的数据格式定义在 CSS(Core Specification Supplement) 规范的 Part A,Section 1 中。
AD Type 的标识值代表的类型定义在 Assigned Numbers 。
扫描响应也包含广播数据。
三、BLE 工作概述
BLE 常见的操作有:
- BLE 设备发送广播。如:物联网设备向外广播数据,表示自己存在;
- 接收 BLE 广播,如:手机可以扫描周围的 BLE 设备发送的广播数据;
- BLE 设备之间建立连接,并实现点对点通信。如手机实现蓝牙灯控。
BLE 常见的工作流程:
下面举一个常见的 BLE 工作流程案列:
环境:一台物联网设备(BLE 温度传感器), 一台智能手机/电脑;
要求:手机/电脑需要去扫描这台物联网设备,并与他建立连接实现数据通信;
工作流程:
-
首先,BLE 温度传感器发送广播数据,向外展示自己的存在;
-
其次,手机/电脑扫描到广播,并与 BLE 温度传感器建立点对点连接;
-
接着,手机/电脑向 BLE 温度传感器发送数据请求;
-
最后,BLE 温度传感器使用温度数据,来响应手机/电脑的数据请求。
四、BLE 使用的协议规范
总结 BLE 工作流程可知,BLE 设备工作时,会处于两种不同的状态:
- 广播 / 扫描状态(无连接);
- 连接状态。
对于不同的状态,蓝牙规范定义了不同的操作协议:
规范说明如下:
规范 | 规范概述 |
---|---|
GAP | GAP定义了 BLE 设备发送广播,扫描广播,建立连接的模式和流程 |
ATT / GATT | ATT 协议定义了属性的概念,属性用于保存数据;GATT 是在 ATT 协议上进一步抽象而来的规范,定义了已链接设备之间的数据存在形式,与数据交换方法 |
`
GAP
GAP 定义归纳了一系列的角色、模式、流程等概念,用户需要首先理解这些概念,然后根据自己的开发需求,按照 GAP 规范去配置使用 BLE,从而实现BLE 设备的广播。如,用户如果需要开发一个收发 BLE 广播的应用程序,那么就需要设置 GAP 定义的相关模式,从而实现广播效果。
1. GAP 工作角色
BLE 工作时,会存在4 种常见的操作,GAP 将这 4 种常见的操作定义为如下 4 种工作角色:
角色说明如下:
应用角色 | 应用特性 |
---|---|
Broadcaster | 用于发送不可连接广播,并对 Observer 发送的扫描请求做出响应,不能与 Observer 建立连接 |
Observer | 接收 Broadcaster 发送的广播,可以选择向 Broadcaster 发送扫描请求,并接收扫描响应 |
Peripheral | 用于发送可连接广播,并根据接收到连接请求与 Central 建立连接 |
Central | 接收可连接广播,并向 Peripheral 发送连接请求,并建立连接 |
2. GAP 工作模式
除了不同的 GAP 角色时, GAP 还定义如下不同的 GAP 模式:
3. GAP 工作流程
与 GAP 模式相对应,GAP 也定义如下 GAP 工作流程:
·
4. GAP 工作角色、模式、流程关系
上文介绍了 GAP 的工作角色、模式、流程,当 GAP 处于不同的角色时,其工作模式和流程都可能不一样,下表详细的介绍了他们之间的关系:
说明:
M:强制支持(Mandatory)
O:可选支持(Optional)
E:不支持(Exclude)
从上图可以看出:
- Broadcaster / Peripheral 不支持任一的 GAP 流程;
- Observer / Central 不支持任一的 GAP 模式。
即:GAP 流程用于扫描广播,GAP 模式用于发送广播。
通过 GAP 建立连接后的 master / salve
当建立连接后,两个 BLE 设备都处于连接状态,此时 peripheral 做为连接状态下的从机, Central 做为连接状态下的主机。
ATT
已连接的 BLE 设备使用 ATT / GATT 规范来进行应用数据交换。
ATT 定义了角色、属性的概念,属性用来来保存数据。
ATT 角色
在典型的手机 - BLE 设备物联网应用中:
- BLE 设备做为 ATT 服务器;
- 手机做为 ATT 客户端。
属性
属性逻辑结构如下:
其中:
- 属性句柄由属性服务器分配;
- 属性类型由用户定义或更高层规范指定;
- 属性值由用户定义或更高层规范指定,用来保存应用数据;
- 属性权限由用户定义或更高层规范指定。
属性逻辑结构总结:
- 属性就好比一个一个的柜子,这个柜子由 ATT 服务器定义而来,每个柜子都存在一个编号,就是属性句柄,用来唯一的指定 ATT 服务器上的一个属性;ATT 服务器对每个柜子都做出了分类,即属性类型 UUID,同一种类型 UUID 的柜子,可以多次出现;属性值即是柜子中真正存储的东西;属性权限是对柜子的使用说明,比如读/写,就相当与从柜子中拿取/存储东西。
属性及其相关概念总结:
属性访问方法 - ATT 协议帧
属性访问方法也就是 ATT 协议帧,在蓝牙规范中被称作 ATT PDU(protocol data unit).
ATT PDU 被 ATT 客户端用来发现、读、写属性,或者被 ATT 服务器用来发送属性的 notication、indication。
ATT PDU 的类型有如下 6 种:
ATT PDU 格式如下:
其中:
- opcode 位域表示了该 ATT PDU 的类型;
- ATT Parameters 位域包含的参数由 opcode 指定;
- Authentication signature 位域也由 opcode 位域的相关参数指定,通常情况下,该位域不存在;
- 1 + N (+ 12) <= ATT_MTU 。
opcode 位域组成如下:
对于 opcode 各位域的解释如下:
位域 | 描述 |
---|---|
Authentication Signature Flag | 该位置 1,表示在 ATT PDU 中存在 Authentication signature |
Command Flag | 该位置1,表示当前 ATT PDU 是否为一个 Command |
method | 该位用来确定 ATT PDU 的类型和数据格式。 |
综上:根据 opcode 的 method 位域的不同,存在不同的 ATT PDU,具体分类如下。
这些 ATT PDU 供上层规范使用,完成各种各样的功能。
GATT
GATT 是为了给应用程序或其他配置文件使用,以便于 ATT 客户端可以跟 ATT 服务器通信。
GATT 定义了使用 ATT 协议 PDU 的框架,这个框架定义了数据交换流程,也定义了应用数据交换格式:服务(service)和特征(characteristics)。
通过 GATT 我们可以发现服务,并读/写或配置对端设备的特征。
典型 GATT 应用实例
下图例举介绍一个典型的 GATT 应用:
其中:
- 电脑做为 GATT 客户端;
- 温度传感器 BLE 设备做为 GATT 服务器;
- 电脑可以启动流程来访问传感器定义的服务与特征。温度传感器定义一些服务与特征(characteristics) ,这些特征(characteristics) 做为温度服务的一部分,并允许电脑访问。
GATT 角色
与 ATT 相同,GATT 也存在两种角色:
GATT 角色是不固定的,只有当启动相应流程时,GATT 角色才被确定,流程结束时 GATT 角色释放。
其中:
- GATT 客户端发送 commands 和 requests 给服务器,并且能接收来自服务器的 response,indications 和 notifications;
- GATT 服务器接收来自客户端的 commands 和 requests 并且发送response,indication 和 notification 给客户端。
GATT 数据结构
GATT 配置文件指定了数据交换的结构。这个结构定义了基本的元素:服务(service)和特征(characteristics)。
所有服务和特征都包含在属性中,属性是承载 GATT 数据的容器。
GATT 数据结构如下图所示:
对于 GATT 数据结构的说明:
- 最顶层是一个 profile,可以理解为一个应用程序,这个应用程序由 1 个或多个服务组成;
- 每一个服务由特征定义和服务引用组成;
- 特征包含一个特征值和特征值相关的其他信息;
- 服务和特征都以属性的形式被 GATT 服务器存储。
关于为什么还要抽象一层 GATT 数据结构的思考与总结:
- GATT 的数据结构(服务)是以一个一个的属性组成的,为什么要在定义了属性之后还要再抽象一层 GATT 呢?沿用之前将属性比作柜子的说法,假设存在这样一种情况:某种蓝牙应用,包含多种功能,如果每一种功能的实现都需要定义一个属性,那么如何保证 ATT 客户端精确的访问对应功能的属性呢?通过 ATT 协议 PDU 来发现属性吗,但也只能发现柜子的编号和柜子的种类,但是你如何确保功能和属性句柄、属性 UUID 之间的关系呢?除非你为每一个功能对应的属性定义一个标准的、通用的 UUID;但是,为每一个功能都定义一个标准的、通用的UUID,不仅繁琐,而且增加了蓝牙应用开发的难度,还限制了蓝牙应用开发的想象力。所以我们需要另外定义一套标准的功能声明结构,通过这个标准的功能声明结构,我们可以查找到 ATT 服务器上存在的功能,以及实现每一个功能对应的一个或多个属性,这就是 GATT 的服务(service)。
- GATT 服务(service)把实现一种功能的属性进行了整合,并可以使用 UUID 对这个功能进行命令。沿用之前将属性比作柜子的说法,GATT 服务(service)相当于一列火车,将实现一种功能的柜子(属性)都搬上了车。ATT 客户端只需查找 ATT 服务器上存在的火车即可发现定义的蓝牙功能及实现这个功能相关的柜子(属性)。
服务(service)
服务是一系列的数据以及完成一个实际功能的相关行为的集合。
在GATT 中,一个服务定义包含:
- 服务声明属性;
- 服务引用(可选);
- 至少一个的特征定义。
GATT 指定了两种服务类型:
这两种服务都是属性组,即包含了一系列的属性。
在 GATT 中,服务通过服务声明定义,服务声明是一个组属性,服务声明属性的逻辑结构如下:
其中:
1.服务声明属性的属性值为服务 UUID,服务 UUID 可以是 SIG 定义的规范服务(16 位),也可以是自定义服务(128 位)。
2. 服务 UUID 用来表示整个服务的类型。
服务是一个属性组,服务的起始句柄是服务声明句柄,服务的结束句柄为下一个服务的服务声明的前一个句柄或 0xFFFF。
服务引用
服务引用是一种将 GATT 服务器上存在的一个服务引用到另一个服务定义中的方法。
为了引用其他服务,在服务定义的开始处必须使用引用定义。
引用定义使用引用声明来引用其他服务,引用声明是一个属性,属性逻辑结构如下:
其中:
- 被引用服务的服务声明句柄,表示服务属性组的起始句柄;
- 被引用服务的服务定义结束句柄,表示服务属性组的结束句柄;
- 被引用的服务 UUID 可以是 16 位的规范 UUID,也可以是 128 位的自定义 UUID;
- 服务声明句柄,服务定义结束句柄,服务 UUID 可以唯一的标识定义在 GATT 服务器上的一个服务。
特征(Characteristic)
每一个特征都被服务所包含,特征中包含了存储应用数据的属性,即特征值属性。
特征通过特征定义来指定,在 GATT 中,每一个特征定义包含:
- 特征声明属性;
- 特征值属性;
- 可选的特征描述符属性。
特征声明属性
特征定义从特征声明属性开始,特征声明属性的逻辑结构如下:
其中,特征值属性访问特性字节主要定义了特征值属性可用于哪些 ATT 访问方法,其各个位定义如下:
特征值属性
特征值属性包含了特征的值,这是真正用于存储应用数据的属性。
特征描述符属性
特征描述符被用来包含特征值有关的信息,特征描述符也是一个属性。
GATT 定义了标准的特征描述符集,这些特征描述符可以被更高层使用;每一个特征描述符使用特征描述符 UUID 标识。
GATT 供定义了 6 中特征描述符,在这里只介绍一个常用的特征描述符:客户端特征配置描述符(CCCD)。
客户端特征配置声明(CCCD)是一个可选的特征描述符,它被客户端配置,使服务器能够以 notification 或 indication 的方式发送特征值给客户端。当特征声明属性的特征值访问特性的 notify 位域和 indicate 位域置 1 时,该特征描述符必须存在。
CCCD 属性逻辑结构如下:
2 字节的特征配置位的位域组成如下:
GATT 功能
GATT 定义了各种功能来完成服务发现与特征访问。GATT 共定义了 11 种功能,这些功能使用 ATT 协议来实现:
两个已连接的 BLE 设备,分别做为 GATT 服务器和 GATT 客户端,其中 GATT 服务器定义服务与特征,GATT 客户端使用上述 GATT 功能来实现 BLE 设备之间的数据交换。
GATT 应用详述
应用目的:手机/电脑与温度传感器 BLE 设备建立连接,并通过 GATT 来读取温度数据。
操作步骤说明:
- 温度传感器和手机/电脑通过 GAP 建立连接;
- 建立连接后,手机/电脑做为 master,温度传感器做为 slave;
- 温度传感器做为 GATT 服务器,定义温度服务(service)和温度特征(characteristic);
- 手机/电脑做为 GATT 客户端,使用主服务发现功能查找温度服务;
- 温度服务查找到之后,手机/电脑使用引用服务发现功能查找温度服务中是否引用了其他服务;
- 手机/电脑使用特征定义发现功能查找温度特征;
- 手机/电脑使用特征描述符发现功能查找温度特征是否存在特征描述符;
- 如果查找到温度特征,手机/电脑可以使用**读特征值功能 **来读取温度特征属性值中保存的温度数据;
- 如果查找到 CCCD 特征描述符,手机/电脑可以使用写特征描述符功能来配置 GATT 服务器发送温度特征的 notification / indication,手机/电脑接收 notification / indication 获得温度数据。