GATT 的全名是 Generic Attribute Profile,它定义了两个BLE设备的数据传输方式和两个概念:Services 和 Characteristics,为属性协议传输和存储数据建立了一些通用操作和框架。它建立在 ATT(Attribute Protocol)协议的基础上,ATT 协议把 Service,Characteristic 对应的数据保存在一个查找表中,查找表使用 16bit ID 作为每一项的索引。
ATT 协议主要是定义了 Attribute(属性)这个数据结构。一个 Attribute 由三个元素组成:
1、16 bit 的句柄(唯一性,用于区分和查找不同的 attribute)
2、UUID(ATT 本身不定义,留给 GATT 来定义)
3、一个定长的值 value(配合 UUID 使用,由 GATT 来决定这个 UUID 的意义和数据)
GATT 协议中的 Service 和 Characteristic 需要遵循 ATT 这种数据结构,ATT 会管理这些数据并提供查找方法。
一旦两个设备建立起了连接,GATT 就开始起作用了,这也意味着,你必需完成前面的 GAP 协议。 这里需要说明的是,GATT 连接,必须先经过 GAP 协议。实际上,我们在 Android 开发中,可以直接使用设备的 MAC 地址,发起连接,可以不经过扫描的步骤。这并不意味不需要经过 GAP,实际上在芯片级别已经给你做好了,蓝牙芯片发起连接,总是先扫描设备,扫描到了才会发起连接。
GATT 连接需要特别注意的是:GATT 连接是独占的。 也就是一个 BLE 外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就是一个 BLE 外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就对其他设备不可见了。当设备断开,它又开始广播。
※ 一个外设只能跟一个中心建立连接(独占的),而一个中心可以同时连接多个外设(一个手机可以同时连接多个BLE设备)
中心设备和外设需要双向通信的话,唯一的方式就是建立 GATT 连接,通过中心来中转。
GATT 连接的网络拓扑
下图展示了 GTT 连接网络拓扑结构。一个外设只能连接一个中心设备,而一个中心设备可以连接多个外设。
GATT 通信事务
GATT 通信的双方是 C/S 关系。外设作为 GATT 服务端(Server),它维持了 ATT 的查找表以及 service 和 characteristic 的定义。中心设备是 GATT 客户端(Client),它向 Server 发起请求。需要注意的是,所有的通信事件,都是由客户端(也叫主设备,Master)发起,并且接收服务端(也叫从设备,Slave)的响应。
一旦连接建立,外设将会给中心设备建议一个连接间隔(Connection Interval),这样,中心设备就会在每个连接间隔尝试去重新连接,检查是否有新的数据。但是,这个连接间隔只是一个建议,你的中心设备可能并不会严格按照这个间隔来执行,例如你的中心设备正在忙于连接其他的外设,或者中心设备资源太忙。
下图展示一个外设(GATT 服务端)和中心设备(GATT 客户端)之间的数据交换流程,可以看到的是,每次都是主设备发起请求:
GATT 结构
GATT 事务是建立在嵌套的Profiles(规范、通讯协议), Services(服务) 和 Characteristics(特征值)之上的的,如下图所示:
Profile
Profile 并不存在于 BLE 外设上的,它只是一个被 Bluetooth SIG 或者外设设计者预先定义的 Service 的集合。例如心率Profile(Heart Rate Profile)就是结合了 Heart Rate Service 和 Device Information Service。所有官方通过 GATT Profile 的列表可以在网站上找到。
Service
Service 是把数据分成一个个的独立逻辑项,它包含一个或者多个 Characteristic。每个 Service 有一个 UUID 唯一标识。 UUID 有 16 bit 的,或者 128 bit 的。16 bit 的 UUID 是官方通过认证的,需要花钱购买,128 bit 是自定义的,这个就可以自己随便设置。
官方通过了一些标准 Service,完整列表可以在网站上找到。以 Heart Rate Service 为例,可以看到它的官方通过 16 bit UUID 是 0x180D,包含 3 个 Characteristic:Heart Rate Measurement, Body Sensor Location 和 Heart Rate Control Point,并且定义了只有第一个是必须的,它是可选实现的。
Characteristic 在 GATT 事务中的最低界别的是 Characteristic,Characteristic 是最小的逻辑数据单元,当然它可能包含一个组关联的数据,例如加速度计的 X/Y/Z 三轴值。
与 Service 类似,每个 Characteristic 用 16 bit 或者 128 bit 的 UUID 唯一标识。你可以免费使用 Bluetooth SIG 官方定义的标准 Characteristic,使用官方定义的,可以确保 BLE 的软件和硬件能相互理解。当然,你可以自定义 Characteristic,这样的话,就只有你自己的软件和外设能够相互理解。
举个例子, Heart Rate Measurement Characteristic,这是上面提到的 Heart Rate Service 必需实现的 Characteristic,它的 UUID 是 0x2A37。它的数据结构是,开始 8 bit 定义心率数据格式,接下来就是对应格式的实际心率数据。
实际上,和 BLE 外设打交道,主要是通过 Characteristic。你可以从 Characteristic 读取数据,也可以往 Characteristic 写数据。这样就实现了双向的通信。所以你可以自己实现一个类似串口(UART)的 Sevice,这个 Service 中包含两个 Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。