这次介绍一下蓝牙协议栈(BLE)的基础知识,蓝牙协议栈组成如下图所示,首先我们说说GAP和GATT
1. GAP(Generic Access Profile)
GAP层是负责连接的,其中包含广播、扫描、连接、断开的过程和参数
1.1 角色
蓝牙设备的角色主要有中心(Central)和外围设备(Peripheral)两种,中心设备向外围设备发起连接。链路层的主机(Master)和从机(Slave)的概念跟中心和外围的概念是对应的。
除了中心和外围之外,还有Observer和Broadcaster角色,Observer一直进行监听,Broadcaster一直进行发送,这两种角色都只广播,不能发起连接或者被连接,这里就不详细说了
1.2 广播
建立连接之前,外围设备每隔一段时间发送一个广播包,让正在扫描的设备知道这是一个可以连接的设备,扫描设备才能对外围设备开始连接,这个广播包的时间间隔叫advertising interval,这个间隔可以在10ms到10.24s之间,间隔的长短会影响建立连接所花时间。
中心要收到广播包之后才能发送连接请求,相应的,外围设备在发送广播包之后会等待连接请求。
蓝牙广播包最多可以包含31字节数据,包含设备名称和一些标志。中心收到广播包之后可以发送Scan Request以请求更多的广播信息,外围设备会回复一个同样是31个字节的Scan Response。
BLE有37个数据信道和3个广播信道,广播包,Scan Request,Scan Response使用广播信道
1.3 扫描
扫描是指中心监听广播包并且发送Scan request。扫描中有两个参数:Scan window(扫描窗口) 和Scan interval(扫描间隔)
1.4 发起连接
中心发起连接的过程类似于扫描的过程,中心收到广播包之后会发送一个连接请求给外围设备
1.5 连接
中心和外围设备连接上之后,中心会按照一定的连接间隔(Connection interval)向外围设备请求数据,这个间隔是由中心定的,在7.5ms到4s之间。
如果要提高吞吐量,可以在一个连接间隔中传输多个数据包,每个包最多可以包含20字节数据。如果要省电,并且外围设备并没有什么数据需要传输,可以跳过几个连接间隔,这称之为Slave latency。
如果外围设备没有在规定时间内响应中心的请求就会认为是连接中断,称之为Supervision Time-out(0.1s-32s),所以在使用Slave latency的时候要注意不要引起Supervision Time-out
这些参数是建立连接的时候中心确定的,如果建立连接之后外围设备想要更改,可以向中心发送Connection parameter update request。
整个数据交换的过程会在不同的频段中跳频(除了广播频段),跳频是自动完成的,不需要我们去管。
2. GATT(Generic Attribute profile)
设备之间的数据传输是在GATT这层完成的
2.1 角色
除了GAP里面的角色,BLE在GATT里面也定义了两个角色,分别是GATT Server 和GATT Client,一般来说产生数据的设备是GATT Server,访问数据的设备是GATT Client,一个设备可以既是GATT Server也是GATT Client。这两个角色跟GAP中的角色并没有关系。
2.2 GATT结构
GATT Server通过属性表(Attribute table)来组织数据,
2.2.1 Attribute
上图中每一行就是一个属性Attribute。
每个属性具有一个handle,一个UUID,和一个Value。
Handle是Attribute的一个索引,每个Attribute的Handle都是唯一的。
UUID(universal unique identifier)表示的是Attribute中数据的类型信息。UUID在一个设备里面不是唯一的,可以有多个Attribute的UUID都一样
2.2.2 Characteristic
可以把Characteristic看作是上图中几行的集合(几个Attribute的集合)
每个Characteristic至少有两个Attribute,其中一个是声明,另一个包含数据。前面说过,蓝牙传输数据是通过GATT来传的,更具体的来说,是通过一个个Characteristic来传的。
2.2.3 Descriptors 描述符
Characteristic除了包含声明和数据之外,还可以有描述符(Descriptors,但不是必须有),Descriptors是用来进一步描述Characteristic(但不提供数据)的Attribute,比如说用自然语言描述该Characteristic是用来干什么的。
有一类特殊的描述符,叫CCCD(Client Characteristic Configuration Descriptor),支持Notify和Indicate的Characteristic 必须包含CCCD
2.2.4 Service
Service 是一个或者多个Characteristic的逻辑组合
一个GATT Service 通常包含了一些相关的功能,举例来说,一个人机界面Service包含了各种人机交互输入输出的数据,而其中的每个Characteristic 是一类信号或者设备
介绍几个常见的Service。
GAP GATT Service:作为Central或者Peripheral的BLE设备都需要有这个Service。这个Service包含了如何发现和连接设备的信息
Generic Attribute Service: GATT Server都要有这个Service,这个Service包含了GATT Server的信息
2.2.5 Profile
一个或者多个Service组合在一起称为Profile。Profile 是逻辑上的概念,自己并不具备单独的Attribute。
2.3 标准和自定义的Service和Characteristic
蓝牙联盟定义了一些标准的Profile, Service, Characteristic 和Attribute。由于Profile和Service是在具体应用中规定的,所以用户可以进行自定义
2.4 UUID
图2中每一个Attribute都有UUID,UUID是一个128位的数字,是用来描述Attribute的类型的
2.4.1 蓝牙联盟UUID
蓝牙联盟把UUID分为基础UUID(base UUID)和16位UUID。
蓝牙联盟规定的UUID都具有同样的base UUID:
0x0000xxxx-0000-1000-8000-00805F9B34FB
蓝牙联盟规定了一些16位UUID,替换掉base UUID中的xxxx就组成一个完整的128位UUID了。举例来说,0x2A37是一个16位Heart Rate Measurement Characteristic,那么对应的128位的UUID就是:
0x00002A37-0000-1000-8000-00805F9B34FB。
由于所有蓝牙联盟的UUID都具有同样的base UUID,所以用16位UUID就可以区分蓝牙联盟规定的Attribute了
但我们自定义的Attribute, Characteristic, Service,不能使用这个base UUID,因此也不能用16位UUID,只能使用制造商自定义的128位UUID。
2.5 空中接口操作和属性
由于每个Attribute具有唯一的Handle,所以几乎所有的操作都是通过Handle去完成,Characteristic常用的属性有:Write, Write without response, Read, Notify, Indicate。 Characteristic的属性决定了我们可以如何使用它
Write, Write without response
这两种属性允许GATT Client 对Server的characteristic的值进行写操作,两者的区别是Write without response对写操作不会有确认
Read
GATT Client可以读Server的Characteristic的值。
Notify 和Indicate
这两种属性表示的是当GATT Server 中该Characteristic 的值发生变化的时候会通知Client。两者的区别是Indicate 会进行确认但Notify不会
3. 示例
接下来举例说明一下前面介绍的概念
Thingy 的Services,作为Server需要有GAP Service和GATT Service,另外还有一个标准的Battery Service,后面是几个自定义的服务
详细的看看GAP Service,这个服务的Handle是1到9,那么把这些Characteristics和Attribute都打出来
可以看到这个Service的结构是这样的
这是一个标准的Service,使用标准Service/Characteristic的时候要符合蓝牙SIG对这个Service/Characteristic的规定,我们可以到蓝牙SIG看看是不是一致
以上就是BLE的一些基础知识和示例