查看: 1568|回复: 0

[技术交流] 【蓝牙】小院闲聊#06#——ATT和GATT的概念

[复制链接]

108

主题

163

帖子

618

积分

利尔达员工

Rank: 9Rank: 9Rank: 9

积分
618
发表于 2019-6-11 18:38:00 | 显示全部楼层 |阅读模式
BLE C/S架构(Client和Server)

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

        一个characteristic包含三种条目:characteristic声明,characteristic的值以及characteristic的描述符(可以有多个描述符):
                characteristicdeclaration就是每个characteristic的分界符,解析时一旦遇到characteristicdeclaration,就可以认为接下来又是一个新的characteristic了,同时characteristic declaration还将包含value的读写属性等。
                Characteristic value就是数据的值了,这个比较好理解就不再说了。
                Characteristicdescriptor就是数据的额外信息,比如温度的单位是什么,数据是用小数表示还是百分比表示等之类的数据描述信息。CCCD是一种特殊的characteristicdescriptor,当characteristic具有notify或者indicate操作功能时,那么必须为其添加相应CCCD,以方便client来使能或者禁止notify或者indicate功能。

        不管是characteristic declaration,characteristic value还是characteristic descriptor,实现的时候,我们都是用attribute来表达的,也就是说,他们每一个都是一个attribute,attribute可以用下图来表示:
1.       Attribute handle
        Attribute句柄。Client要访问Server的Attribute,都是通过这个句柄来访问的,也就是说ATT PDU一般都包含handle的值。用户在软件代码添加characteristic的时候,系统会自动按顺序地为相关attribute生成句柄。
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层,低功耗蓝牙也可以通信起来,但会产生兼容性问题以及通信的低效率。
3.       Attribute value
        就是数据真正的值,0到512字节长。
4.       Attribute permissions
        Attribute的权限属性,权限属性不会直接在空中包中体现,而是隐含在ATT命令的操作结果中。目前主要有如下四种权限属性:
                l Open,直接可以读或者写
                l No Access,禁止读或者写
                l Authentication,需要配对才能读或者写,由于配对有多种类型,因此authentication又衍生多种子类型,比如带不带MITM,有没有LESC
                l Authorization,跟open一样,不过server返回attribute的值之前需要应用先授权,也就是说应用可以在回调函数里面去修改读或者写的原始值。
                l Signed,签名后才能读或者写,这个用得比较少。


        Client和Server之间是通过ATT PDU来通信的,ATT PDU主要包括4类:读,写,notify和indicate。如果一个命令需要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等。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表