像GAP层实现大多数连接相关的功能一样,BLE低功耗协议栈的GATT层被应用程序用于实现两个连接设备的数据通信。数据以特性的形式传递和存储,这些特性存储在蓝牙低功耗设备的存储器中。站在GATT层角度看,两个连接的设备分别处于GATT服务器和GATT客户端两个角色之一。
(1)GATT服务器:
这种设备包含特性数据库,供客户端读或者写访问。
(2)GATT客户端:
这种设备从服务器读或者写数据。
GATT的角色和GAP的角色是相互独立的存在,集中器可以是GATT服务器,也可以是GATT客户端,外部设备也一样。
参考蓝牙低功耗的描述,特性和属性从概念上有时可互换。特性可以看成是一个集合,而属性就像是特性的子集。实际上,设备之间传输的信息就是特性。特性约定和使用属性作为value(数值)、properties(权限)和configuration information(配置信息)。典型的特性由以下几个属性组成:
Characteristic Value | 特性值 | 顾名思义,就是特性的值 |
---|---|---|
Characteristic Declaration | 声明 | 描述权限、位置还有特性值的类型 |
Client Characteristic Configuration | 配置 | 允许GATT服务器配置特性为notified(通知)(异步发送消息)或者indicated(指示)(有响应地异步发送消息) |
Characteristic User Description | 描述 | 用ASCII码字符串描述该特征 |
*注:后面两个(配置和描述)可选。
这些属性存储在GATT服务器属性表中,除了value之外,其他属性都有以下的Properties(这里不就再译为属性了,避免混淆):
(1)Handle:属性在表格中的索引(每个属性有独一无二的句柄)
(2)Type:指明属性数值代表的是什么(UUID),有些UUID是SIG技术联盟定义的,有些是用户自定义的
(3)Permissions: GATT客户端设备对属性值的访问权限
这是什么意思呢?可以看看下面的表格:
句柄 | 类型uuid | Value |
---|---|---|
0x0010 | Primary Service | Link loss |
0x0011 | Characteristic | (rw, 0x0012, Alert Level) |
0x0012 | Alert Level | 0x00 |
0x0020 | Primary Service | Tx Power |
0x0021 | Characteristic | (r, 0x0022, Tx_Power dBm) |
0x0022 | Tx_Power dBm | 0x04 |
0x0030 | Primary Service | Immediate Alert |
0x0031 | Characteristic | (w, 0x0032, Alert Level) |
0x0032 | Alert Level |
属性Property是最小可寻址的数据单元,可以通过16BIT的Handle句柄寻址,它的类型UUID可以是16BIT的、32BIT的甚至是128BIT的(这里简单说一下UUID,UUID有些是蓝牙技术连门SIG定义的,有些是我们用户自己定义的,完整的UUID都是128BIT长度,我们遇到的很多16bit的UUID只是SIG定义的128BITUUID中的一部分,而我们用户自定义的UUID,那么这128Bit都可自己定义),属性有一个数据域,其字节数最高达512字节。总结,ATT协议定义属性由句柄、UUID、数值组成。一个Characteristic至少包含一个数值属性和一个声明属性,数值属性的意义定义在Profile中,声明总是出现在数值属性的前面,用于描述数值属性是否具备读或者写、特性的UUID以及特性值的句柄(可以从上表体会)。
一个Peer device(这里你可以简单理解为GATT客户端设备)可以通过属性的句柄寻址,并且设备只能对属性进行空中操作。在无线传输协议中并没有服务和特性的概念,仅有属性的概念,意思就是说蓝牙无线传输都是传的属性,设备端自行将收到的解析成服务和特性。
GATT客户端抽象层,GATT客户端没有属性表或者配置文件,不存在服务信息。分层如下:
作为GATT服务器,大多数的GATT功能都有独自的GATT配置文件(profiles)封装。这些profiles使用GATTServApp(TI是用这个模块,名字就叫做 GATTServApp,应该其他蓝牙芯片也有相似的模块)来存放和管理属性表 。
上面的图片是 GATT Server的分层框架,可见,比客户端的多了两层,分别是GattServApp、Profiles。
前面说到特性是属性的集合,那么这里提到的GATT Service是特性的集合。举个例子,心率服务包含:心率检测特性,体位特性,还有其他特性,多种服务可以组合在一起构成一个服务配置文件。
Gatt服务可以给每个特性各自定义访问权限,每个服务允许一些特性可以被任何客户端访问,同时也可以为认证客户端限制其他特性的访问权限,对于我们用户自己 定义的服务配置文件,我们可以根据自己的需求定义合适的权限。
需要认证的特性必须在客户端通过配对认证方式后才能访问。这种验证在协议栈里面实现,不需要用户应用程序实现,我们写程序只需要把特性正确的注册到GATT服务中。举个例子,下面给出某配置文件中的其中一个特性,这个特性的权限是认证读。
// Example:
{
{ ATT_BT_UUID_SIZE, ExampleUUID },
GATT_PERMIT_AUTHEN_READ,
0,
&examplestring[0]
},
当一个未认证的客户端尝试读取这个特性,服务器会返回ERROR_INSUFFICIENT_AUTHEN(0x41),可以用蓝牙数据分析仪抓取空中包查看。
逻辑链路控制及自适应协议层的协议数据单元字节大小定义了ATT最大传输单元的字节大小。默认地,低功耗设备规定了PDU的字节大小是27字节,一般MTU的字节大小是PDU字节大小减去4,因此这里默认的MTU字节大小是23字节,我们配置PDU字节大小也就决定了MTU的字节大小。在集中器和外部设备建立连接的过程中会交换MTU信息,双方协商使用两个MTU中最小的一个。
如果使能安全连接BLE 4.2特性,设备默认支持MTU为65字节,这是LE安全连接所需要的。实际上在两个设备进行数据通信之前MTU仍然必须通过MTU交换过程进行协商,所有连接将以默认的MTU 23字节开始。MTU增大,意味着在一帧ATT包中能容纳的字节也就多了,减少了数据分包的情况。
该服务包含设备和访问信息,比如设备名、厂商ID、产品ID。该服务定义了以下的特性:
Device Name |
---|
Appearance |
Peripheral preferred connection parameters |
GAP GATT Service(GGS)是蓝牙低功耗设备实现集中器和外部设备角色所必须的。多重角色设备也必须包含有GGS。GGS的作用是设备发现和连接初始化过程。
·怎么使用GAP GATT SERVICE呢?
拿TI的蓝牙芯片来举个例子,首先包含协议栈的gapgattserver.h文件,初始化GGS参数,将GAP GATT服务添加到GATT服务器中。
Generic Attribute Profile(GATT),通用属性配置文件,它提供在设备上注册的GATT服务信息,从应用程序角度看,它更像是一个属性表。为了能在你自己的应用程序中使用属性表信息,必须先将属性表添加到协议栈GATT Server里面,因此属性表隶属的服务才能被公开到GATT Client,Client也能够请求服务。