蓝牙BLE: ATT和GATT的概念

BLE通信由两种设备类型构成—— Client和Server。

Server提供数据服务,所以一般来说设备是Server,手机是Client。Server和Client通过ATT PDU进行交互,Server通过characteristic对数据进行封装。多个characteristic组成一个Service,一个Service是一个独立的服务单元,或者说service是一个基本的BLE应用。如果某个service是一个蓝牙联盟定义的标准服务,也可以称其为profile,比如HID/心率计/体温计/血糖仪等,都是标准蓝牙服务,因此都有相应的profile规格书。

一. characteristic

一个characteristic包含三种条目:characteristic声明,characteristic的值以及characteristic的描述符(可以有多个描述符):

1.1 Characteristic declaration

就是每个characteristic的分界符。解析时一旦遇到characteristicdeclaration,就可以认为接下来又是一个新的characteristic了,同时characteristic declaration还将包含value的读写属性等。

1.2 Characteristic value

就是数据的值了,这个比较好理解就不再说了。

1.3 Characteristic descriptor

就是数据的额外信息。比如温度的单位是什么,数据是用小数表示还是百分比表示等之类的数据描述信息。CCCD是一种特殊的characteristicdescriptor,当characteristic具有notify或者indicate操作功能时,那么必须为其添加相应CCCD,以方便client来使能或者禁止notify或者indicate功能。

不管是characteristic declaration,characteristic value还是characteristic descriptor,实现的时候,我们都是用attribute来表达的,也就是说,他们每一个都是一个attribute,attribute可以用下图来表示:

 

二. Attribute

2.1 Attribute handle

 Attribute句柄。Client要访问Server的Attribute,都是通过这个句柄来访问的,也就是说ATT PDU一般都包含handle的值。用户在软件代码添加characteristic的时候,系统会自动按顺序地为相关attribute生成句柄。

2.2 Attribute type

  Attribute类型。在BLE中我们使用UUID来定义数据的类型,UUID是128 bit的,所以我们有足够的UUID来表达万事万物。其中有一个UUID非常特殊,它被蓝牙联盟采用为官方UUID,这个UUID如下所示:0000xxxx-0000-1000-8000-00805F9B34FB, 由于这个UUID众所周知,蓝牙联盟将自己定义的attribute或者数据只用16bit UUID来表示,比如0x1234,其实它也是128bit,完整表示为:

  00001234-0000-1000-8000-00805F9B34FB = 16 bit UUID 0x1234

 Attribute type一般是由service和characteristic规格来定义,站在蓝牙协议栈角度来看,ATT层定义了一个通信的基本框架,数据的基本结构,以及通信的指令,而GATT层就是前文所述的service和characteristic,GATT层用来赋予每个数据一个具体的内涵,让数据变得有结构和意义。换句话说,没有GATT层,低功耗蓝牙也可以通信起来,但会产生兼容性问题以及通信的低效率。

2.3  Attribute value

 就是数据真正的值,0到512字节长。

2.4 Attribute permissions

 Attribute的权限属性,权限属性不会直接在空中包中体现,而是隐含在ATT命令的操作结果中。目前主要有如下四种权限属性:

  ●Open,直接可以读或者写

  ●No Access,禁止读或者写

  ●Authentication,需要配对才能读或者写,由于配对有多种类型,因此authentication又衍生多种子类型,比如带不带MITM,有没有LESC

  ●Authorization,跟open一样,不过server返回attribute的值之前需要应用先授权,也就是说应用可以在回调函数里面去修改读或者写的原始值。

  ●Signed,签名后才能读或者写,这个用得比较少。

 

Client和Server之间是通过ATT PDU来通信的,ATT PDU主要包括4类:notifyindicate。如果一个命令需要response,那么会在相应命令后面加上request;如果一个命令只需要ACK而不需要response,那么它的后面就不会带request。这里要特别强调一点,BLE所有命令都是“必达”的,也就是说每个命令发出去之后,会立马等ACK信息,如果收到了ACK包,发起方认为命令完成;否则发起方会一直重传该命令直到超时导致BLE连接断开。换句话说,只要你的BLE没有断开,那么你之前发送的数据包,不管它是用什么ATT PDU来发送的,它肯定被对方收到了。我估计很多人对此会产生疑问,因为他们经常碰到丢包的情况,其实大家经常碰到的“丢包”,不是空中把包丢了或者包在空中被干扰了,而是大家发送的代码写得有问题,导致你要发送的包没有被安全送达到协议栈射频FIFO中,所以以后大家碰到丢包情况,请先检查你的代码,保证你的数据包正确完整安全地送达到协议栈射频FIFO中,只要数据包放到了协议栈射频FIFO中,蓝牙协议栈就能保证该数据包“必达”对方。既然每个ATT命令都必达对方,那么还需要request做什么?如果一个命令带有request后缀,那么发起方就可以收到命令的response包,这个response包在应用层是有回调事件的,而前述的ACK包在应用层是没有回调事件的。所以采用request/response方式,应用层可以按顺序地发送一些数据包,这个在很多应用场合是非常有用的。相反,如果你对应用层数据包的顺序没有要求,那么就可以不使用request/response形式。另外Request/response有一个副作用:大大降低通信的吞吐率,因为request/response必须在不同的连接间隔中出现,也就是说,你在间隔1中发送了一个request命令,那么response包必须在间隔2或者稍后间隔中回复,而不能在间隔1中回复,这就导致两个连接间隔最多只能发一个数据包,而不带request后缀的ATT命令就没有这个问题,在同一个连接间隔中,你可以同时发多个数据包,这样将大大提高数据的吞吐率。

常用的带request的命令:所有read命令,writerequest,indication等,而常用的不带request的命令有write command,notification等。

转自:ATT与GATT概念

 

posted @ 2019-12-04 15:38  夜行过客  阅读(10480)  评论(1编辑  收藏  举报