六 蓝牙低功耗(BLE)协议栈 之 GATT层

时间:2024-04-02 09:33:16

一 介绍

ATT 一文中说,属性就相当于是一个类中的各个变量,那么GATT就相当于是将这些变量按照一定规则组合起来就成了一个完整的类。

GATT(Generic Attribute Profile, 通用属性规范),自己本身不提供数据,而是将ATT层提供的属性组合起来构成的服务。通过ATT层可以读写对端设备的属性值,各个属性之间有什么联系各个属性之间怎么组合起来的,是由GATT层负责。服务是GATT层的关键字,服务由属性组成。

二 服务的结构

一个BLE设备可以由多个服务组成,一个服务可以包含多个特征(characteristic),一个特征可以包含多个属性。
六 蓝牙低功耗(BLE)协议栈 之 GATT层

1 service声明

一个service从声明它开始,到下一个service声明结束,或者一直持续到最大的handle值。

所谓的声明也是一个属性,这个属性的type为0x2800或0x2801,表示这是一个首要服务(Primary Service)或者次要服务(Secondary service).

它的value用来表示这是什么服务,即value就是这个service的UUID。

permission表示这个该声明即这个ATT属性是只读的、无需验证的、无需授权的。从这里可以看到蓝牙设备能够提供什么服务是公开的,它无法隐藏,别的设备都可以来查询该设备提供了什么服务。

六 蓝牙低功耗(BLE)协议栈 之 GATT层

Attribute Type的类型如下图:

六 蓝牙低功耗(BLE)协议栈 之 GATT层

2 characteristic声明

一个characteristic从声明开始到下一个characteristic的声明结束,或者直到下一个service声明开始,或者一直持续到handle最大值结束。

characteristic = characteristic声明 + characteristic value声明 + 可能的descriptor。

characteristic的声明结构如下图:

六 蓝牙低功耗(BLE)协议栈 之 GATT层

characteristic declaration也是一个ATT属性,type为 0x2803,它的value比较特殊有3项内容:

  • a) properties(特性性质),1个字节,Properties决定了Value的访问方式,可以是多个值的组合,比如可以是(read, write)或者(Notify)等。properties的取值如下图所示

六 蓝牙低功耗(BLE)协议栈 之 GATT层

  • b) value handle 2个字节,表示characteristic value的ATT属性的handle。也就是说在characteristic declaration这个属性中已经确定了characteristic的值,通过handle指向另外一个ATT属性。
  • c) UUID 表示characteristic value的ATT属性的UUID,2个或者16个字节

characteristic value声明 也是一个属性,这一属性的handle、type等于characteristic 声明的 b) c)两项。

3 characteristic value声明

六 蓝牙低功耗(BLE)协议栈 之 GATT层

characteristic声明和characteristic value声明关系如下:

六 蓝牙低功耗(BLE)协议栈 之 GATT层

4 characteristic descriptor声明

descriptor的类型:

  • Characteristic Extended Properties
  • Characteristic User Description
  • Client Characteristic Configuration
  • Server Characteristic Configuration
  • Characteristic Presentation Format
  • Characteristic Aggregate Format

characteristic descriptor也是一个属性,不同类型的descriptor格式也不相同。

六 蓝牙低功耗(BLE)协议栈 之 GATT层

六 蓝牙低功耗(BLE)协议栈 之 GATT层

六 蓝牙低功耗(BLE)协议栈 之 GATT层
Descriptor属于可选条目,也就是说,一个characteristic可以不包含任何一条descriptor。这里着重提一种特殊的descriptor:CCCD。一般而言,都是client来访问server的characteristic,即通过ATT读或者写PDU访问相关数据。如果server想直接把自己的characteristic的值告诉client,就需要通过notify或者indicate PDU,跟其他PDU相比,这2个PDU是由server自己决定什么时候开始传送,而不是被动接受client的命令请求。但client毕竟是客户啊,它得有自主权,所以引入了一个CCCD来帮助client控制server的行为。client可以通过禁止CCCD以不接收 notify或者indicate命令,client也可以通过使能CCCD以允许notify或者indicate命令。重新总结一下,当CCCD使能的情况下,server可以随时notify或者indicate数据给client;当CCCD禁止的时候,哪怕server有数据,它也不能notify或者indicate给client。这里强调一下,当characteristic具有notify或者indicate操作功能时,蓝牙规范要求必须为其添加CCCD attribute。

三 定义一个服务

一个蓝牙设备可以有多个service,一个service可以有多个characteristic,一个characteristic可以有多个属性(一个声明属性properties,一个value属性,0个或多个Descriptor)。向协议栈添加一个服务实际上就是在flash中开辟一块空间,然后将这些service的相关信息保存在这里。

六 蓝牙低功耗(BLE)协议栈 之 GATT层
上图中是蓝牙官方文档提供的一个服务的例子包含三个属性:server声明、characteristic声明、characteristic值

  1. service的声明(是一个属性)
  • handle = 0x0001 用来在这个蓝牙设备中唯一标识这个属性
  • primary service 这个字段用来告诉协议栈当前属性的类型, 表示它是一个首要服务,它的值为0x2800,当协议栈从flash中读到这个是值时它就知道一个首要服务开始了。
  • 《GAP Servicce》 用来表明是一个服务,就是UUID
  1. characteristic的声明(是一个属性)
  • handle = 0x0004 用来标识一个属性
  • characteristic = 0x2803 用来标识这是一个characteristic的开始,当协议栈从flash中读到这个值得时候就知道接下来就是一个characteristic了。
  • {0x02, 0x0006, 《Device Name》} 这个属性值比较特殊
    • 0x02 是一个property
    • 0x0006 是指定了这个characteristic的值得handle
    • 《Device Name》 是指handle为0x0006的属性的类型
  1. 用来描述characteristic的值(是一个属性)
  • handle = 0x0006 用来标识一个属性
  • 《Device Name》 是一个UUID
  • “Example Device” 属性的值,一个字符串

四 访问一个服务

GATT层定义了11个Feature,用来表示GATT层可以做哪些事情

  1. Server Configuration (配置服务)
  2. Primary Service Discovery (发现主要服务)
  3. Relationship Discovery (发现相关的服务)
  4. Characteristic Discovery (发现特性)
  5. Characteristic Descriptor Discovery (发现特性的描述信息)
  6. Reading a Characteristic Value (读特性的值)
  7. Writing a Characteristic Value (写特性的值)
  8. Notification of a Characteristic Value (server主动通知特性的值)
  9. Indication of a Characteristic Value (server主动指示特性的值)
  10. Reading a Characteristic Descriptor (读特性的描述信息)
  11. Writing a Characteristic Descriptor (写特性的描述信息)

这11项Feature通过procedure(规程)来实现,而procedure要通过ATT层的Request、Response等操作来传输数据。

比如Server Configuration这个feature,需要通过"Exchange MTU"这个规程来实现;具体的操作需要Client向server发出"Exchange MTU Request" ,而server可能回复"Exchange MTU Response"或"Error Response"

server 和 procedure、ATT的关系:

六 蓝牙低功耗(BLE)协议栈 之 GATT层

下面是一个发现所有主服务的例子:

六 蓝牙低功耗(BLE)协议栈 之 GATT层