原文:https://epx.com.br/artigos/bluetooth_gatt.php

蓝牙4.0版本推出了低功耗规范,引入了两个核心协议:ATT(Attribute Protocol)和GATT(Generic Attribute Protocol).这两个协议主要目标是BLE,但是也可以运行在传统蓝牙上(BR/EDR).

Overview

ATT是wire applicationprotocol(怎么翻译?连接协议?),GATT基于ATT协议。所有的BLE profile一定基于GATT。也就是所有的BLE服务都使用ATT作为应用协议。

锁定BLE使用这两个协议的好处是:

1, 开发和实现新的BLEprofile更加容易,因为不需要从头实现wire protocol。

2, ATT针对BLE 设备进行了特别的优化:使用尽可能少的字节,因此可能在存储中使用定长结构来生成PDU。

3, ATT/GATT的简单意味着固件可能提供某种程度的协议支持,省去了微处理器软件的麻烦。

4, 对于软件实现的协议栈来说,ATT/GATT在协议栈里实现,省去了应用的麻烦。

5, 即使有的场景下,ATT/GATT不够理想。也可以在L2CAP连接上实现平行于ATTchannel的协议。

ATT: Attribute Protocol

ATT协议的唯一基础是属性。每个属性由三个元素构成:

1,一个16bit handle;

2,一个UUID来定义属性的类型;

3,确定长度的属性值

在ATT中,属性值可以是任意长度的byte数组。属性值的实际意义依赖于UUID,而且ATT并不会检查属性值长度是否与给定的UUID定义一致。

Handle是用来唯一识别属性的数字,因为在一个BLE 设备中可能存在多个属性具有相同的UUID。

ATT协议本身没有定义任何UUID。这部分工作留给了GATT和上层协议。

ATT server存储属性。ATT client什么也不存储,它使用ATT协议来读写server端的属性。

和属性相关的还有读写权限。读写权限存在属性值里,由高层协议确定。ATT本身不会关心,也不会试图解释属性值来确定权限。这部分工作也留给了GATT和上层协议。

ATT有一些良好的特征,比如通过UUID来搜索属性,通过handle区间范围来获取所有区间内的属性,因此client不需要提前获得handle的值,也不需要高层协议硬编码这些值。

但是在特定的设备上handle的取值最好保持不变,这样的话client能够缓冲信息。在第一个discovery以后,client能够使用缓冲信息,这样能够减少传输的包数量,也能够节约能量。如果服务端的属性布局已经发生了变换,高层协议应该能够”暗示”client,比如固件升级。

大多数情况下ATT协议都是纯C/S架构,client发起请求,server响应。但是服务端也有通知的能力,在服务端属性发生变化时,server能够通知client,这样避免了client不停的poll。

ATT协议不会显式发送属性值的长度,只能从PDU长度里面获得。因此client最好能够知道某种UUID类型所代表的属性的精确结构。

不发送属性值长度,是为了减少发送的字节,因为LE的MTU只有23bytes。

23bytes的MTU对于较长的属性值来说是个麻烦。因此不得采用“read long”,”write long“这样的操作。

ATT是如此通用,意味着高层协议有太多工作要做。过度的自由也会带来问题,比如:如果一个设备提供多个服务怎么办?对每一个设备只有一个ATT handle空间,多个服务不得不共享同一份空间。

幸运地是,我们还有GATT,它为我们提供了属性用法,并解除了这些限制。

GATT:Generic Attribute Profile

GATT是所有LE顶层协议的基础。它定义了怎么把一堆ATT属性分组成为有意义的服务。

GATT services

GATT service的基础是UUID值为0x2800的属性。所有跟在这个属性后面的属性都属于这个属性定义的服务,直到另一个0x2800属性出现。

比如说,一个设备里面的三个属性布局如下:

每一个属性不知道它自己属于哪个服务,GATT需要根据0x2800属性作为标记来识别出哪个属性属于哪个服务。

按照这个定义,handle值就有意义了。在上面的例子中,属于service B的属性handle必须位于0x0151和0x02ff之间。

UUID 0x2800定义了primary 服务,也可以使用0x2801来定义secondary 服务。Secondary 服务表示包含于primary 服务。

然后我们怎么能知道一个服务是温度计,智能钥匙或者GPS?答案是通过读取属性值。服务属值包含了一个UUID,通过这个UUID区分服务。

因此,每个属性定义事实上包含了两个UUID,0x2800或者0x2801作为属性UUID,另外一个属性值里面存储的UUID。后面这个UUID是服务ID。

举个栗子:

在图中, thermometer service的UUID是0x1816。

是不是有点晕啊?两个UUID定义一个服务?这是GATT/ATT分层方式导致的后果。UUID 0x2800被GATT用来寻找服务定义边界。一旦找到了边界,属性值,也就是第二个UUID用来指定服务。这样client能够找到所有的服务而不需要知道服务的具体定义。

GATT service characteristics

每一个服务有几个特征。特征存储了有用的值以及权限。

比如,一个温度计可能有只读的温度特征,也可能有可读写的时间戳。

每一个服务可能有几个特征,这些特征也是通过路碑属性来发现的。

主特征的UUID是0x2803,然后主特征的属性值用来定义特征。比如图中 0x2803用来找到特征,0x2A2B用来找到特征包含的信息。

每一个特征至少包含两个属性,主属性0x2803和真正的值属性。主属性知道属性值的handle和UUID。这能够进行一定程度的交叉检测。

特征值的真正格式是由UUID决定的。因此,如果客户端知道如何解释UUID为 0x2A08的特征值,就能够从包含这个特征任何服务里面读取日期和时间。当然如果客户端不知道如何解释这个UUID的话,也可以选择忽略。

Characteristic descriptors

除了特征值,我们也可以为每个特征增加更多的属性。在GATT语法里,这个额外的属性成为描述符。

举个栗子,我们也许需要指定温度的计量单位。

GATT知道handle 0x0104是特征0x0101的描述符,因为:

1, 他不是特征的值,因为特征值的handle应该是0x0102

2, 他的handle落在了0x0103-0x010f之间,因此也不属于下一个特征。

描述符值的意义依赖于属性UUID。例子中,描述符的UUID是0x2A1F,客户端如果不能识别这个UUId,他可以选择忽略。这样可以实现向下兼容。

每个服务可能定义自己的描述符,但是GATT已经定义了能够覆盖大多数情况的标准描述符,比如:

数值格式和表示;

人类可读的描述;

合理范围扩展属性等等。其中特别重要的描述符是client characteristic configuration。

Client Characteristic Configurationdescriptor

Client Characteristic Configurationdescriptor的UUID是0x2902,具有一个16bit的可读写值,作为一个bitmap来使用。

这个属性被server用来存储和代表每个已经绑定的client的独立实例,每个client只能看到它自己的拷贝。

前两个bit被GATT用来定义通知和暗示。其他bit暂时未使用。

通过设置CCC,client能够让server在特征发生改变时得到通知。比如包含了CCC的属性布局如下:

Servicediscovery in Low Energy

因为GATT中所有的服务细节通过ATT来描述,所以不需要像BR/EDR那样设置专门的服务发现协议。ATT负责一切:发现服务,查找特征,读写值等等。

GATT andvanilla Bluetooth

GATT也可以工作在传统蓝牙上面,但是规范规定传统蓝牙仍然使用SDP发送服务,即使通过GATT来进行实际数据交换。

这样的好处是在双模设备上不用设置标识来识别LE-only服务。如果一个服务只能通过GATT发现,就是LE-only。如果能够通过GATT和SDP发现,就是双模。

如果一个profile通过GATT来进行数据交换,并且是双模的,它必须首先发布SDP record。然后这个服务通过SDP来发现,然后通过GATT来查找特征。

当然,现在没有双模的profile。以前的profile是BR/EDR only,并且没有适配到GATT;LE-only只有LE。

如果想要测试GATT而没有LE硬件,可以修改蓝牙协议栈来使BR/EDR可以进行GATT discovery。这是规范不运行的,但是开发者可以。

Notificationsversus connections

通知和暗示使得server可以发送消息给client。这样客户端不需要pollserver来获取新的数据。

另外,典型的GATT server是“小的“外设,像非常需要节能的传感器之类。因此,外设的LE 设备不能发起连接。那么通知怎么发送呢?

在BLE协议栈,如果server有数据发送,它就进入广播模式,并且发送一些信号。每个profile定义了广播时长和频率。时长和频率应该根据使用场景进行了节能和及时性的权衡。

处于中心模式的设备随时处于监听模式。当它监听到广播后,如果发现广播设备是认识的(配对过或者白名单中的),就会向外设发起连接。

连接建立以后,GATT通信能够进行,通知得以发送。所以典型的序列是:1,server发送广播 2,client连接 3server通知

如果没有更多的数据发送,server和client就会超时断开。最佳超时时间依赖于用例;如果服务不会频繁发送通知并且没有实时性要求的话,可以立马断开。因为BLE重连是非常快的。

典型的GATT server是外设设备,但是不是必须的。也可以外设做client,center做server。在这种场景下,client想要读写数据的时候,需要先进入广播模式。

蓝牙低功耗profile:ATT和GATT

蓝牙4.0版本推出了低功耗规范,引入了两个核心协议:ATT(Attribute Protocol)和GATT(Generic Attribute Protocol).这两个协议主要目标是BLE,但是也可以运行在传统蓝牙上(BR/EDR).

Overview

ATT是wire applicationprotocol(怎么翻译?连接协议?),GATT基于ATT协议。所有的BLE profile一定基于GATT。也就是所有的BLE服务都使用ATT作为应用协议。

锁定BLE使用这两个协议的好处是:

1, 开发和实现新的BLEprofile更加容易,因为不需要从头实现wire protocol。

2, ATT针对BLE 设备进行了特别的优化:使用尽可能少的字节,因此可能在存储中使用定长结构来生成PDU。

3, ATT/GATT的简单意味着固件可能提供某种程度的协议支持,省去了微处理器软件的麻烦。

4, 对于软件实现的协议栈来说,ATT/GATT在协议栈里实现,省去了应用的麻烦。

5, 即使有的场景下,ATT/GATT不够理想。也可以在L2CAP连接上实现平行于ATTchannel的协议。

ATT: Attribute Protocol

ATT协议的唯一基础是属性。每个属性由三个元素构成:

1,一个16bit handle;

2,一个UUID来定义属性的类型;

3,确定长度的属性值

在ATT中,属性值可以是任意长度的byte数组。属性值的实际意义依赖于UUID,而且ATT并不会检查属性值长度是否与给定的UUID定义一致。

Handle是用来唯一识别属性的数字,因为在一个BLE 设备中可能存在多个属性具有相同的UUID。

ATT协议本身没有定义任何UUID。这部分工作留给了GATT和上层协议。

ATT server存储属性。ATT client什么也不存储,它使用ATT协议来读写server端的属性。

和属性相关的还有读写权限。读写权限存在属性值里,由高层协议确定。ATT本身不会关心,也不会试图解释属性值来确定权限。这部分工作也留给了GATT和上层协议。

ATT有一些良好的特征,比如通过UUID来搜索属性,通过handle区间范围来获取所有区间内的属性,因此client不需要提前获得handle的值,也不需要高层协议硬编码这些值。

但是在特定的设备上handle的取值最好保持不变,这样的话client能够缓冲信息。在第一个discovery以后,client能够使用缓冲信息,这样能够减少传输的包数量,也能够节约能量。如果服务端的属性布局已经发生了变换,高层协议应该能够”暗示”client,比如固件升级。

大多数情况下ATT协议都是纯C/S架构,client发起请求,server响应。但是服务端也有通知的能力,在服务端属性发生变化时,server能够通知client,这样避免了client不停的poll。

ATT协议不会显式发送属性值的长度,只能从PDU长度里面获得。因此client最好能够知道某种UUID类型所代表的属性的精确结构。

不发送属性值长度,是为了减少发送的字节,因为LE的MTU只有23bytes。

23bytes的MTU对于较长的属性值来说是个麻烦。因此不得采用“read long”,”write long“这样的操作。

ATT是如此通用,意味着高层协议有太多工作要做。过度的自由也会带来问题,比如:如果一个设备提供多个服务怎么办?对每一个设备只有一个ATT handle空间,多个服务不得不共享同一份空间。

幸运地是,我们还有GATT,它为我们提供了属性用法,并解除了这些限制。

GATT:Generic Attribute Profile

GATT是所有LE顶层协议的基础。它定义了怎么把一堆ATT属性分组成为有意义的服务。

GATT services

GATT service的基础是UUID值为0x2800的属性。所有跟在这个属性后面的属性都属于这个属性定义的服务,直到另一个0x2800属性出现。

比如说,一个设备里面的三个属性布局如下:

每一个属性不知道它自己属于哪个服务,GATT需要根据0x2800属性作为标记来识别出哪个属性属于哪个服务。

按照这个定义,handle值就有意义了。在上面的例子中,属于service B的属性handle必须位于0x0151和0x02ff之间。

UUID 0x2800定义了primary 服务,也可以使用0x2801来定义secondary 服务。Secondary 服务表示包含于primary 服务。

然后我们怎么能知道一个服务是温度计,智能钥匙或者GPS?答案是通过读取属性值。服务属值包含了一个UUID,通过这个UUID区分服务。

因此,每个属性定义事实上包含了两个UUID,0x2800或者0x2801作为属性UUID,另外一个属性值里面存储的UUID。后面这个UUID是服务ID。

举个栗子:

在图中, thermometer service的UUID是0x1816。

是不是有点晕啊?两个UUID定义一个服务?这是GATT/ATT分层方式导致的后果。UUID 0x2800被GATT用来寻找服务定义边界。一旦找到了边界,属性值,也就是第二个UUID用来指定服务。这样client能够找到所有的服务而不需要知道服务的具体定义。

GATT service characteristics

每一个服务有几个特征。特征存储了有用的值以及权限。

比如,一个温度计可能有只读的温度特征,也可能有可读写的时间戳。

每一个服务可能有几个特征,这些特征也是通过路碑属性来发现的。

主特征的UUID是0x2803,然后主特征的属性值用来定义特征。比如图中 0x2803用来找到特征,0x2A2B用来找到特征包含的信息。

每一个特征至少包含两个属性,主属性0x2803和真正的值属性。主属性知道属性值的handle和UUID。这能够进行一定程度的交叉检测。

特征值的真正格式是由UUID决定的。因此,如果客户端知道如何解释UUID为 0x2A08的特征值,就能够从包含这个特征任何服务里面读取日期和时间。当然如果客户端不知道如何解释这个UUID的话,也可以选择忽略。

Characteristic descriptors

除了特征值,我们也可以为每个特征增加更多的属性。在GATT语法里,这个额外的属性成为描述符。

举个栗子,我们也许需要指定温度的计量单位。

GATT知道handle 0x0104是特征0x0101的描述符,因为:

1, 他不是特征的值,因为特征值的handle应该是0x0102

2, 他的handle落在了0x0103-0x010f之间,因此也不属于下一个特征。

描述符值的意义依赖于属性UUID。例子中,描述符的UUID是0x2A1F,客户端如果不能识别这个UUId,他可以选择忽略。这样可以实现向下兼容。

每个服务可能定义自己的描述符,但是GATT已经定义了能够覆盖大多数情况的标准描述符,比如:

数值格式和表示;

人类可读的描述;

合理范围扩展属性等等。其中特别重要的描述符是client characteristic configuration。

Client Characteristic Configurationdescriptor

Client Characteristic Configurationdescriptor的UUID是0x2902,具有一个16bit的可读写值,作为一个bitmap来使用。

这个属性被server用来存储和代表每个已经绑定的client的独立实例,每个client只能看到它自己的拷贝。

前两个bit被GATT用来定义通知和暗示。其他bit暂时未使用。

通过设置CCC,client能够让server在特征发生改变时得到通知。比如包含了CCC的属性布局如下:

Servicediscovery in Low Energy

因为GATT中所有的服务细节通过ATT来描述,所以不需要像BR/EDR那样设置专门的服务发现协议。ATT负责一切:发现服务,查找特征,读写值等等。

GATT andvanilla Bluetooth

GATT也可以工作在传统蓝牙上面,但是规范规定传统蓝牙仍然使用SDP发送服务,即使通过GATT来进行实际数据交换。

这样的好处是在双模设备上不用设置标识来识别LE-only服务。如果一个服务只能通过GATT发现,就是LE-only。如果能够通过GATT和SDP发现,就是双模。

如果一个profile通过GATT来进行数据交换,并且是双模的,它必须首先发布SDP record。然后这个服务通过SDP来发现,然后通过GATT来查找特征。

当然,现在没有双模的profile。以前的profile是BR/EDR only,并且没有适配到GATT;LE-only只有LE。

如果想要测试GATT而没有LE硬件,可以修改蓝牙协议栈来使BR/EDR可以进行GATT discovery。这是规范不运行的,但是开发者可以。

Notificationsversus connections

通知和暗示使得server可以发送消息给client。这样客户端不需要pollserver来获取新的数据。

另外,典型的GATT server是“小的“外设,像非常需要节能的传感器之类。因此,外设的LE 设备不能发起连接。那么通知怎么发送呢?

在BLE协议栈,如果server有数据发送,它就进入广播模式,并且发送一些信号。每个profile定义了广播时长和频率。时长和频率应该根据使用场景进行了节能和及时性的权衡。

处于中心模式的设备随时处于监听模式。当它监听到广播后,如果发现广播设备是认识的(配对过或者白名单中的),就会向外设发起连接。

连接建立以后,GATT通信能够进行,通知得以发送。所以典型的序列是:1,server发送广播 2,client连接 3server通知

如果没有更多的数据发送,server和client就会超时断开。最佳超时时间依赖于用例;如果服务不会频繁发送通知并且没有实时性要求的话,可以立马断开。因为BLE重连是非常快的。

典型的GATT server是外设设备,但是不是必须的。也可以外设做client,center做server。在这种场景下,client想要读写数据的时候,需要先进入广播模式。

蓝牙低功耗profile:ATT和GATT相关推荐

  1. Bluetooth profile: ATT/GATT(襄坤在线)

    蓝牙4.0版本推出了低功耗规范,引入了两个核心协议:ATT(Attribute Protocol)和GATT(Generic Attribute Protocol).这两个协议主要目标是BLE,但是也 ...

  2. 【Android应用开发】Android 蓝牙低功耗 (BLE) ( 第一篇 . 概述 . 蓝牙低功耗文档 翻译)

    转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/50515359 参考 :  -- 官方文档 : https://develope ...

  3. MDK5 nRF BLE(蓝牙低功耗)

    BLE(蓝牙低功耗) 1 什么是蓝牙低功耗? BLE是蓝牙低功耗的简称(Bluetooth Low Energy).BLE技术是低成本.短距离.可互操作的鲁棒性无线技术,工作在免许可的2.4GHz I ...

  4. 【Android】BLE:蓝牙低功耗基础

    一.蓝牙概述 蓝牙是一种短距离通信的无线电技术.特点: 1.分散式网络结构 2.点对点或多点通信 3.快跳频和短包技术 4.工作在2.4GHz ISM(工业,科学,医学缩写)频段 5.时分全双工传输 ...

  5. 蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍

    原文链接:蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍 系列索引:蓝牙协议分析(1)_基本概念 蓝牙协议分析(2)_协议架构 目录 1. 前言 2. Why 3. How和What 4. Phy ...

  6. DA14580-01UNA蓝牙低功耗4.2 SoC 无线收发器和基带处理器DIALOG

    DA14580-01UNA DA14580蓝牙低功耗4.2 SoC最终概述DA14580集成电路具有完全集成的无线收发器和基带处理器,用于Blue-tooth®低功耗. 它可用作独立应用程序处理器或托 ...

  7. ATT 和 GATT 协议学习

    文章目录 1 ATT(Attribute protocol) 1.1 基本概念 1.2 属性 PDU 1.2.1 属性 PDU 格式 1.2.2 顺序协议 1.3 属性协议 PDU 1.3.1 Rea ...

  8. BLE学习(3):ATT和GATT详解

    本文章将介绍在面向连接的蓝牙模式中,ATT(attribute protocol,属性协议)和GATT(generic attribute profile,通用属性配置文件)这两个重要的协议层,它与蓝 ...

  9. 【FRDM-KW41Z学习笔记】运行蓝牙低功耗无线UART应用

    本文主要介绍了使用Kinetis KW41Z双无线模式片上系统(SoC)的Freescale Freedom开发平台的蓝牙低功耗堆栈.软件开发包提供了兼容蓝牙低功耗v4.2的主机栈和实现一组基于GAT ...

最新文章

  1. 武大+CMU最新开源!全面支持平面/鱼眼/球面相机的实时统一线段检测算法
  2. Bootstrap排版中地址与引用详解
  3. python 文本向量化_Python文本特征抽取与向量化算法学习
  4. 客户每次请求Web页面过程
  5. Docker Machine搭建并加入节点
  6. java启动servlet_Java Servlet 运行原理分析
  7. 在 Mac 上的 Safari 浏览器中如何存储网页的一部分或整个网页?
  8. CentOS 8 的安装(官方安装、清华大学开源软件镜像站、阿里云镜像、网易镜像下的安装步骤)
  9. 基于Java的试题库管理系统(论文+毕业设计)(完整源码可演示)
  10. java循环26个字母_java基础 26个英文字母循环输出 13个字母空一行
  11. MySQL varchar类型可以存储多少个汉字
  12. 鲁大师电动车智能化测评报告第十七期:电动车产品的同质化困局
  13. 【总结】1396- 60+个 VSCode 插件,打造好用的编辑器
  14. jenkins编译打包及自动化部署
  15. HDOJ 1282 回文数猜想
  16. 【pwn】2022 极客大挑战
  17. ESP32开发(一):搭建windows开发环境--ESP-IDF工具命令提示符操作
  18. ffmpeg中av_log的实现分析
  19. 表单控件 文本框 title overall type: UNKNOWN_TYPE server type: NO_SERVER_DATA
  20. 基于CVSS3.1的一种评估框架

热门文章

  1. php对数字字符串加解密
  2. 数据结构国际象棋中的马跳棋盘问题
  3. 896. 最长上升子序列 II
  4. Kubernetes系列教程(二)---集群网络之Flannel核心原理
  5. outlook 2016 邮件怎么显示图片
  6. (攻防sj)web-bug
  7. 工厂设计模式—java
  8. LeetCode算法,每日一题,冲击阿里巴巴,day7
  9. 乐鑫科技2022笔试面试题
  10. 【翻译】硅谷创业教父保罗·格雷厄姆:做不可拓展的事 Do things that don't scale...