ATT(Attribute) protocol为所有基于LE link的应用提供了一个底层的框架。它定义了server与client,定义了属性以及client如何获取server端的一系列属性。Generic Attribute Profile作为一个通用的基于ATT的profile,为上层应用提供了一个基本的服务框架(service framework),使得所有基于LE的应用都可以将自身的功能映射到这个框架中来。
相比ATT protocol,GATT Profile定义了以下更为具体的概念:
- 一组通用的Attribute Type,如Primary Service、Characteristic;
- 以上通用Attribute Type的Attribute Value的格式,不是所有的Attribute Value都只有一个UUID;
- 如何使用ATT PDU对这组通用的Attribute进行读写、查询、配置;
- 上层应用要如何基于GATT定义自己的Service
Attribute Type
GATT定义了以下通用的Attribute Type:
Attribute Type | UUID | Description |
---|---|---|
《Primary Service》 | 0x2800 | 基础服务,通常包含《Include》以及《Characteristic》 来描述它的具体特性 |
《Secondary Service》 | 0x2801 | 二级服务 |
《Include》 | 0x2802 | 通常被包含在另一个Primary Service中,表示当前Service 用到了这个《Include》service。它的Attribute Value包含了 《Include》service的Attribute Handle、End Group Handle。 如果这个《Include》Service的UUID是BT SIG定义的 16bit UUID,则还包含这个UUID值 |
《Characteristic》 | 0x2803 | 服务的特性,包含Property和Value,以及零或多个Descriptor (下面都是Descriptor)。所有的Descriptor都是用来 描述《Characteristic》的。 |
《Characteristic Extended Properties》 | 0x2900 | 扩展属性Descriptor,《Characteristic》本身只有一个字节 来描述它的property,更多属性将在这个Descriptor中说明 |
《Characteristic User Descriptor》 | 0x2901 | 对某个《Characteristic》的描述,是一个UTF-8格式的字符串 |
《Client Characteristic Configuration》 | 0x2902 | GATT的client可以通过配置这个Descriptor,来使能 对应《Characteristic》的notification或Indication。 不同的GATT client有各自独立的 《Client Characteristic Configuration》 |
《Server Characteristic Configuration》 | 0x2903 | 也是一个GATT client可以配置的Descriptor,可以使能 Server的“Broadcast”特性,即将该Descriptor所属的 《Characteristic》的value放在LE广播包中进行传输。 和《Client Characteristic Configuration》不同的是, 所有GATT client共享一个 《Server Characteristic Configuration》 |
《Characteristic Format》 | 0x2904 | 描述了Characteristic Value的格式,比如一个温度计的 度数所呈现的格式 |
《Characteristic Aggregate Format》 | 0x2905 | 一组《Characteristic Format》Descriptors的handle的集合, 每个handle指向一个《Characteristic Format》 |
以上,《Primary Service》、《Secondary Service》和《Characteristic》属于ATT protocol中定义的“group of attributes”。Service由其声明(declaration)、《Include》和《Characteristic》组成一个group。《Characteristic》则由其声明、Value以及隶属于它的Descriptors组成。《Primary Service》、《Secondary Service》都可以通过“Read By Group Type Request”来查询它们的起止handle,而《Characteristic》则需要多个procedure的组合来查询它的所有信息。
有了以上的几个“group of attributes”的概念,一个完整的GATT Profile的层级视图就可以用下面的图大致勾画出来了:
注意到在上面的图中,《Include》、Descriptors都是用虚线框表示的。因此,一个最简单的GATT层级图,将只有一个Service的描述、一个Characteristic的描述以及Characteristic的Value组成。此外,上图并没有单独列出Service的声明,而实际上它就是Service这个group的第一个Attribute。
Primary Service
关于Service的格式,Spec定义如下图:
首先,它的Attribute Type就是前面说的一个GATT定义的通用的Attribute Type。其次,Attribut Value字段就是UUID,一般是上层应用的Service UUID。BT SIG已经定义了一些,比如HID Service为0x1812,这些UUID都可以直接用16bit来表示;如果需要自己定义一个Service,就需要使用一个128-bit的UUID了。最后,Attribute Permission描述了Service的权限为可读。这也就是ATT protocol规定的由上层(这里就是GATT Profile)来定义的permission。
Characteristic
一个Service的主要特性由它的Characteristic来说明。它可以是《Device Information Service》中用于描述厂商信息的《PnP_ID》,只能用于client读取;也可以是《HID Service》中的《HID Report》,用于将HOGP device(GATT Server)的按键消息传送给HOGP Host(GATT Client)。一个Characteristic由声明、Value以及零或多个Descriptors组成。声明的格式如下:
在这里,Characteristic Declaration这个Attribute的Value由properties、value attribute handle和UUID三个部分组成。除了Characteristic,其他也有很多的通用Attribute Type的Value是由多个字段组成的。
Characteristic Properties是一个单字节的bit mask,格式如下:
不同于ATT protocol定义的Attribute Permission,它涉及的主要是如何使用Characteristic,而不是access的权限。部分bit,如Notify和Indicate,一旦置位为1,就意味着这个Characteristic将包含一个《Client Characteristic Configuration》Descriptor。GATT client可以通过这个Descriptor来配置使能/禁能Characteristic的notification或indication。此外,Extended Properties和前面提到的《Characteristic Extended Properties》相关,由这个Descriptor来说明扩展的properties。
Characteristic Value Attribute Handle是保存Characteristic本身的value的handle值。Characteristic UUID由上层定义,比如《HID Service》中的《Report Map》的UUID为0x2A4B。
Characteristic Value的Attribute格式如下:
注意到,这里的Attribute Type是上层定义的。这也是GATT Profile当中唯一一个Type由上层定义的Attribute。其实它就是前面Characteristic声明中Attribute Value的Characteristic UUID字段。本身就是上层定义的,因此它的Attribute Permissions也是上层来决定的。每个基于GATT的profile都需要定义自己的Characteristic及其permissions。
GATT Feature Requirements
其实在我看来,介绍完通用的Attribute Type及其存储格式之后,GATT Profile的工作就完成了。在Spec中,Feature这一章介绍的是如何使用ATT的protocol PDUs来获取那些通用Attribute Type的信息。比ATT更为具体的是,GATT Profile定义了不同Attribute Type具有不同的Attribute Value格式。对一个Characteristic Value handle进行read,返回的结构肯定与读取一个Characteristic Declaration返回的不同。因此,可以将这章介绍到的procedure,当做ATT protocol PDUs那节的具体的例子来看。
GATT Service
这里的GATT Service是GATT Profile为自己定义的一个Service,它的UUID为0x1801。它存在的意义在于,它包含了一个Service Changed Characteristic。一旦server端的GATT属性分布有变(增加了或者移除了一些信息),server就可以通过这个Characteristic的indication来通知client(前提是,client配置过server的《Client Characteristic Configuration》,允许server进行indicate)。Service Changed Characteristic的格式如下:
Service Changed Characteristic具有固定的properties——0x20,这意味着它只能通过indication来告知自身的变化。它的Value Handle包含了发生变化的Attribute的起止handle,client可以对这个范围内的所有Attribute重新进行查询。
其他
ATT protocol提到了“ATT Bearer”的概念,GATT对其进行了具体的解释。并不是只有LE link才能承载ATT,经典的BR\EDR link也可以传输ATT数据。不同的是,对于LE link而言,ATT使用fixed L2CAP channel(channel ID为0x0004),PDU不可被flush,断开ATT Bearer就意味着断开LE link。而在BR\EDR传输ATT时,使用PSM(0x001F)来动态分配L2CAP channel ID,MTU size也由L2CAP signal channel进行配置。基于LE link的GATT,加密是可选项目;而在BR\EDR link上使用GATT就必须先加密。最后,列出GATT的SDP record: