蓝牙学习六(GATT)

news2024/9/22 21:34:55

1.简介

        GATT-Generic Attribute profle-通用属性配置文件。GATT层是传输真正数据所在的层。包括了一个数据传输存储架构以及其基本操作GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理。没有GATT,BLE协议栈也能跑。但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profile,BLE摆脱了Zigbee等无线协议的兼容性困境,成为了出货量最大的2.4G无线通信产品。

2.角色

        GATT定义了两类角色服务端(server)和客户端(client),GATT角色无需和GAP角色绑定,但是可能由更高层的规范进行指定。

        除了GAP定义角色外(GAP定义广播者扫描者外围设备中央设备),BLE还定义了另外2种角色:GATT服务端GATT客户端。这两种角色完全独立于GAP的角色。提供数据的设备被称为GATT服务端访问GATT服务端而获得数据的设备被称为GATT客户端。即一个设备可以同时作为客户端和服务端。通常情况下,外围设备为服务端,提供数据。手机作为客户端,访问数据。

3.GATT的规范层次

         一个GATT服务器通过一个称为属性表的表格组织数据,这些数据就是用于真正发送的数据。

3.1属性(Attribute)

         属性协议(Attribute Protocol)简称ATT。是GATT和GAP的基础

        就属性来说,一个属性其实就是一条数据,属性是BLE数据提供单元,也是蓝牙空中传播数据的最上层,BLE开发过程中接触最多的就是这一层。

        一个属性包含了句柄UUID。数据的结构如下图:

  

3.1.1Attribute Handle

         属性句柄(Attribute Handle)占2个字节,犹如指向属性实体的指针,对端设备可以通过属性句柄来访问该属性

        属性句柄值的范围:0x0000 ~ 0xFFFF

3.1.2 Attribute Type

        属性类型(Attribute type)是用来区分当前属性是服务项还是特征值等,一般用UUID来表示。

        UUID(universally unique identifier,通用唯一识别码)是一个软件构建标准,并非BLE独有的概念,一个合法的UUID,一定是随机的,全球唯一的,不应该出现两个相同的UUID。但是在一个GATT表中可能有许多属性,这些属性可能有相同的UUID

       分类

        BLE的属性类型主要有四个大类

        Primary Service(首要服务项):0x2800

        Secondary Service(次要服务项):0x2801

        Include(包含服务项):0x2802

        Characteristic(特征值):0x2803

        常用的UUID:

        Characteristic Extended Properties(特性扩展性质):0x2900

        Characteristic User Description(特性用户描述):0x2901

        Client Characteristic Configuration(客户端特性配置):0x2902

        Server Characteristic Configuration(服务器特性配置):0x2903

        Characteristic Presentation Format(特性表示格式):0x2904

        Characteristic Aggregate Format(特性聚合格式):0x2905

        客户端特性配置描述符:支持通知或指示的特性必须使用该描述符

         取值范围

        0x1800 – 0x26FF :服务项类型
        0x2700 – 0x27FF :单位
        0x2800 – 0x28FF :属性类型
        0x2900 – 0x29FF :描述符类型
        0x2A00 – 0x7FFF :特征值类型

        

        长度

        UUID即可以是2字节也可以是16字节。因为一些常用的UUID,为了减少传输的数据量,BLE协议做了一个转换约定。给定一个固定的16字节模板,只设置2个字节为变化量其他为常量。2字节的UUID在系统内部会被替换,进而转换成保准的16字节的UUID。

        UUID模板为:

        

         而2字节的UUID则替代上边的XXXX。例如心率测量特性使用0X2A37作为它的16位UUID,因此它完整的16字节的UUID为:0x00002A37-0000-1000-8000-008005F9B34FB。

        蓝牙技术联盟所用的基本UUID不能用于任何定制的属性、服务和特性。对于定制的属性,必须使用完整的16字节UUID

3.1.3 Attribute Value

        属性值,就是该条属性数据包含的有效负载。

3.1.4 Attribute Permissions

        属性权限/属性许可,作用是保护Attribute Value

        Attribute Permissions不会直接在空中包中体现,而是隐含在ATT命令的操作结果中

        权限属性

  •         访问权限(Access Permission)-只读,只写,读写
  •         禁止访问权限(No Access)-禁止读或者写
  •         加密权限(Encryption Permission)-加密,不加密
  •         认证权限(Authentication Permission)-需要认证,无需认证。认证是指相互确认对方身份。完成认证流程的两个设备,双方建立信任关系,二者之间的通信通道即可认为是安全的。BLE中,认证过程就是配对
  •         授权权限(Authorization Permission)-需要授权,无需授权
  •         签名权限(Signed Permission)-签名后才能读或写,这个用得比较少

        认证授权功能很容易混淆,其英文拼写也很相似。从上面的概念上看,授权要求设备必须是可信任的,因此授权的管控等级要高于认证--认证的设备未必被授权,授权的设备一定是认证的。理解二者关系后,需要引入一个概念:Trusted Device(可信任设备)一个没有经过认证的设备,被称为Unknown Device(未知设备);经过了认证后,该设备会在绑定设备信息中被标记为Untrusted,被称为Untrusted Device(不可信设备);经过了认证,并且在绑定信息中被标记为Trusted的设备被称为Trusted Device(可信设备)。

        授权要求设备为Trusted Device(可信任设备)。在实际使用中,经过配对以后设备即为Untrusted Device--认证,在代码中调用API可以设置设备为Trusted Device--授权

       

        大部分的空中操作事件都是采用句柄来进行的,因为句柄能够唯一识别各个属性。如何使用特性依据他的性质,特性的性质包括:

  •        
  •         没有回应的写
  •        
  •         通知:客户端发请求服务端,不需要服务端回复一个响应
  •         指示:客户端发请求给服务端,需要服务端回复一个响应。

        写和没有回应的写

        这两个权限允许GATT客户端写一个值到GATT服务端的一个特性中。他们之间不同的地方在与没有回应的写事件没有任何应用层上的确认或回应

        读

        读性质标明一个GATT客户端可以读取在GATT服务端中特性的值

        通知和指示

        通知和指示性质允许GATT服务端在其某个特性改变的时候对GATT客户端进行提醒。通知和指示之间不同之处在与指示有应用层上的确认,而通知没有

        注:ClientServer之间是通过ATT PDU来通讯的,ATT PDU主要包括4类:通知指示。如果一个命令需要response,那么会在相应的指令后面加上request。如果一个命令只需要ACK而不需要response,那么后面就不会带request。这里要特别强调一点,BLE所有命令都是“必达”的,也就是说每个命令发出去之后,会立刻等ACK信息,如果收到了ACK包,发起方认为命令发送完成。否则发起方会一直重发该命令直到超时导致BLE连接断开。换句话说,只要BLE没有断开,那么发送的数据包,一定会被对方收到

        那既然每个ATT命令都必达对方,那么为什么还需要request呢?如果一个命令带有request后缀,那么发起方就可以收到命令的response包,这个response包在应用层是有回调事件的,而ACK包在应用层是没有回调事件的。所以采用request/response方式,应用层可以按顺序地发送一些数据包,这个在很多应用场景中是非常有用的。相反,如果对应用层数据包的顺序没有要求,那么就可以不使用request/response形式。另外request/response有一个副作用大大降低通信的吞吐率。因为request/response必须在不同的连接间隔中出现。也就是说,如果在间隔1中发送了一个request命令,那么response包必须在间隔2或者稍后间隔中回复,而不能再间隔1中回复。这就导致两个连接间隔最多只能发一个数据包,而不带quest后缀的ATT命令就没有这个问题,在同一个连接间隔中,可以同时发送多个数据包,这样就大大提供数据的吞吐率。

        常用的带request的命令:所有读命令,写,指示等。而常用的不带request的命令有没有回应的写,通知等。

3.2 特性

        一个特性至少包含2个属性:一个属性用于声明,一个属性用于存放属性的值
所有通过GATT服务传输的数据必须映射成一系列的特性,可以把特性中的这些数据看成是一个个捆绑起来的数据。每个特性就是一个自我包容而独立的数据点。例如,如果几个数据总是一起变化,那么可以把它们集中在一个特性里。

3.3 描述符

        任何在特性中的属性不是定义为属性值,就是为描述符。描述符是一个额外的属性提供更多的特性信息。它提供一个人类可识别的特性描述的实例。

        然而,有一个特别的描述符需要特别注意:客户端特性配置表述符(Client Characteristic Configuration Descriptor,CCCD),这个描述符是给任何支持通知指示功能的特性额外增加的。在CCCD中写入“1”使能通知功能,写入“2”使能指示功能,写入”0“同时禁止通知和指示功能。

3.4 服务

        一个服务包含一个或多个特性,这些特性是逻辑上相关的集合体。

        GATT服务一般包含几块具有相关性的功能,比如特定传感器的读取和设置,人机接口的输入和输出。组织具有相关的特性到服务中即实用又有效。因为它使得逻辑上和用户数据上的边界变得更加清晰,同时它也有助于不同应用程序间代码的重用。GATT基于SIG蓝牙技术联盟官方设计,SIG建议根据用户自己的规范设计自己的profile。

3.5 profile(数据配置文件)

        一个profile文件可以包含一个或多个服务,一个profile文件包含需要的服务信息或者是与设备如何交互的配置文件选项信息。设备的GAP和GATT的角色都可能在数据的交换过程中改变,因此,这个文件应该包含广播的种类、所使用的连接间隔、所需的安全等级等信息。

注:一个Profile中的属性表不能包含另一个属性表

4 标准的定制服务和特性

        SIG蓝牙技术联盟已经定义了一些profile、服务、特性和根据协议栈的GATT层定义的属性。但是协议栈中只实现了一部分应用的BLE服务。那就意味着,只要协议栈支持GATT,就可能为一个应用建立一个它需要的profile和服务。既然在一个应用中可以支持profile和服务,那么就可以在这个应用中建立一个个人定制的服务

        每个设备都包含以下必要的特征值和服务项:

PROFILE

  •         Generic Access Service(Primary Service)
  •                 Device Name(Characteristic)
  •                 Apperance(Characteristic)
  •         Generic Attribute Service(Primary Service)
  •                 Service Changed(Characteristic)
  •                         CCCD(Descriptor)

         服务项这种类型本身并不包含数据,仅仅相当于是一个容器,用来容纳特征值特征值用来保存用户数据,但是它也有自己的UUID。在处理特征值所携带的用户数据之前,需要先对特征值自身进行声明

        特征值在系统中的表达形式是:声明 + 特征值属性。比如上边Generic Access Service服务项的Device Name特征值,它在GATT数据库中表示方式是:

Characteristic 声明: 0x0002, 0x2803, access_property, 0x2A00
Characteristic 项:   0x0003, 0x2A00, access_property, data

        其中,第一列2个字节代表属性句柄。第二列2个字节代表属性类型(UUID)。0x2803表示该项为“特征值的声明”。0x2A00表示该特征值是Device Name。在第一行特征值声明中,最后一项的属性值就是该特征值的UUID。可以看到,第一行声明里面的属性值0x2A00,而第二行属性值自己的属性类型(UUID)也是0x2A00,信息冗余了。原因是,假如特征值的UUID为自定义的16字节UUID,在特征值的属性类型(UUID)中,只能存放2个字节,而16字节的UUID全称,就只能存放在特征值声明的属性值项中。例如:

Characteristic 声明: 0x0002, 0x2803, access_property, 0x0000ABCD1212efde1523785feabcd123
Characteristic 项:   0x0003, 0xABCD, access_property, data

        BLE的属性体系在系统中以GattDB表示,即属性数据库。在CyBle_gatt.c文件中,可以看到cyBle_gattDB变量,如下:

const CYBLE_GATTS_DB_T cyBle_gattDB[0x10u] = { 
    { 0x0001u, 0x2800u /* Primary service                     */, 0x00000001u /*           */, 0x0007u, {{0x1800u, NULL}}                           }, 
    { 0x0002u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd        */, 0x0003u, {{0x2A00u, NULL}}                           }, 
    { 0x0003u, 0x2A00u /* Device Name                         */, 0x00000201u /* rd        */, 0x0003u, {{0x0009u, (void *)&cyBle_attValuesLen[0]}} }, 
    { 0x0004u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd        */, 0x0005u, {{0x2A01u, NULL}}                           }, 
    { 0x0005u, 0x2A01u /* Appearance                          */, 0x00000201u /* rd        */, 0x0005u, {{0x0002u, (void *)&cyBle_attValuesLen[1]}} }, 
    { 0x0006u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd        */, 0x0007u, {{0x2A04u, NULL}}                           }, 
    { 0x0007u, 0x2A04u /* Peripheral Preferred Connection Par */, 0x00000201u /* rd        */, 0x0007u, {{0x0008u, (void *)&cyBle_attValuesLen[2]}} }, 
    { 0x0008u, 0x2800u /* Primary service                     */, 0x00000001u /*           */, 0x000Bu, {{0x1801u, NULL}}                           }, 
    { 0x0009u, 0x2803u /* Characteristic                      */, 0x00002201u /* rd,ind    */, 0x000Bu, {{0x2A05u, NULL}}                           }, 
    { 0x000Au, 0x2A05u /* Service Changed                     */, 0x00002201u /* rd,ind    */, 0x000Bu, {{0x0004u, (void *)&cyBle_attValuesLen[3]}} }, 
    { 0x000Bu, 0x2902u /* Client Characteristic Configuration */, 0x00000A04u /* rd,wr     */, 0x000Bu, {{0x0002u, (void *)&cyBle_attValuesLen[4]}} }, 
    { 0x000Cu, 0x2800u /* Primary service                     */, 0x00000001u /*           */, 0x0010u, {{0xCBBBu, NULL}}                           }, 
    { 0x000Du, 0x2803u /* Characteristic                      */, 0x00001A01u /* rd,wr,ntf */, 0x0010u, {{0xCBB1u, NULL}}                           }, 
    { 0x000Eu, 0xCBB1u /* Custom Buffer                       */, 0x00011A04u /* rd,wr,ntf */, 0x0010u, {{0x00C8u, (void *)&cyBle_attValuesLen[5]}} }, 
    { 0x000Fu, 0x2901u /* Custom Descriptor                   */, 0x00010001u /*           */, 0x000Fu, {{0x001Cu, (void *)&cyBle_attValuesLen[6]}} }, 
    { 0x0010u, 0x2902u /* Client Characteristic Configuration */, 0x00010A04u /* rd,wr     */, 0x0010u, {{0x0002u, (void *)&cyBle_attValuesLen[7]}} }, 
}; 

        通过注释可以看到,每个特征值都有声明特征值项两部分组成。

        由于每个属性的句柄是递增的,因此属性的声明顺序会影响句柄的计算

        描述符是特征值的补充信息挂载在特征值之下,它可以开辟一段数据空间以携带数据,客户端可以像操作特征值一样对其进行读写,但是描述符弱于特征值,它不具备Notify/Write等读写属性,远不如特征值灵活。有一种描述符叫CCCD(Client Characteristic Configuration Description),当对特征值设置Notify或Indication时,用以控制Notify和Indication的使能情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/67692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

查题接口系统

查题接口系统 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 题库:题库后台(点击跳转) 题库…

Bootstrap-jqgrid学习(十六)

jqgrid网站地址: jqGrid demos-jqGrid实例-中文-mn886.nethttps://blog.mn886.net/jqGrid/ 表格属性 分页属性: pagerstring定义翻页用的导航栏,必须是有效的html元素。翻页工具栏可以放置在html页面任意位置 显示总条数 viewrecordsbo…

#分支语句详解

第一章 C语言:分支语句 文章目录第一章 C语言:分支语句前言1、什么是语句?2.分支语句(选择结构)2.1 if语句2.1.1 悬空else2.1.2 if书写形式的对比2.2 switch语句2.2.1 在switch语句中的 break2.2.2 default子句2.2.3 练…

基于频谱的GCN的数学原理

参考链接:如何理解GCN?知乎回答:从热传导模型到GCN从CNN到GCN的联系与区别——GCN从入门到精(fang)通(qi) GCN问题本质 图中的每个结点无时无刻不因为邻居和更远的点的影响,而在改…

基于linux的操作系统的通用启动流程(一)

这篇我们讲解linux的通用启动流程,按照我们一贯的方式总分总的节奏,因为后面的每个子系统也很大,所以我们讲解子系统的时候也是按照总分总的方式。注意因为基于linux的各式各样的操作系统绝对不下100个,像嵌入式,然后我们的桌面有fedora,redhat,centos,debian,ubuntu以…

如何定位线上CPU占用过高的问题

系列文章目录 文章目录系列文章目录前言一、定位CPU的流程是什么?二、实操1.测试代码样例2.定位问题实践过程总结前言 一、定位CPU的流程是什么? 项目上线,CPU飙高不下,触发报警,如何定位排查问题。有两种办法1、通过…

JVM内存布局及GC原理

“java的内存布局以及GC原理”是java开发人员绕不开的话题,也是面试中常见的高频问题之一。 java发展历史上出现过很多垃圾回收器,各有各的适应场景,很多网上的旧文章已经跟不上最新的变化。本文详细介绍了java的内存布局以及各种垃圾回收器的…

著名运动员刘诗雯从政,迎来人生高光时刻,张继科还般配吗

曾经有这么一句话:中国男足谁都踢不过,中国乒乓球谁都打不过。也间接地说明了国球队伍人才济济。在众多优秀乒乓球队员当中,刘诗雯最近相当耀眼,听说她已经高升当官了,也和张继科拉开了距离。 据悉,公元202…

Java高效率复习-数据类型和运算符[Java]

第一篇关于JavaSE内容的文章 文章的风格比较涣散,但是都是干货,关于Java系列的,还有就是,我认为只有MySQL基础和JavaSE基础是可以做到可操作性和可执行性较强的。 如果像JavaWeb或者SSM框架这些,光看文章你是根本执行…

tensorflow的GPU加速计算

参考 tensorflow的GPU加速计算 - 云社区 - 腾讯云 一、概述 tensorflow程序可以通过tf.device函数来指定运行每一个操作的设备,这个设备可以是本地的CPU或者GPU,也可以是某一台远程的服务器。tensorflow会给每一个可用的设备一个名称,tf.…

PaO2/FiO2在临床中的应用 氧合指数

主任提问:患者呼吸衰竭时的“氧合指数”大约多少?如何计算?_腾讯新闻 (qq.com) 在 ARDS 柏林定义中,诊断低氧血症需要 PaO2/FiO2≤ 300 mmHg,并可以分为轻中重三个等级(下表)。 ARDS 患者的 PaO2/FiO2越低,死亡率越高,其中重度 ARDS 死亡率高达 45%。需要注意这里 …

生产报工管理系统可以帮助企业解决哪些问题?

随着时代的变迁和信息化技术的发展,市场对制造企业在产品价格、质量以及生产成本等方面提出了更高的要求,车间生产也逐渐向着实时化、透明化和可视化方向发展。其中产报工与跟踪是生产管理中重要的环节,自然是不可缺少信息化的。 企业在报工…

Linux基本命令

目录操作 格式:指令 -[参数] [目录] 1. pwd (Print Working Direcotry) 查看当前工作路径 2. cd (Change Direcotry) 改变 shell 工作目录 3. ls (List Files) 列出当前目录下的文件和目录 ls -[参数] [目录] ls的参数均是短命令,可以使用-后添…

经过物联网技术的设备改造有“大脑”,更智能

物联网是通讯网与互联网的拓展应用和网络延伸,通过网络传输互联,进行计算、处理和知识挖掘,实现人与物、物与物的信息交互和无缝链接,达到对物理世界的实时控制、精确管理和科学决策是目的。而物联网设备是一种非标准计算设备&…

【微信小程序】使用npm并引入vant-weapp组件库

0 前言 vant文档与微信小程序文档写得弯弯绕绕,你引用我,我引用你,还给出了多种不同情况下的选项,甚至有步骤缺失,导致踩了一点小坑,浪费了一些没必要的时间,这里给出完整可行的实现方法&#…

Android Studio详细的安装下载教程

一、下载Android Studio 1、进入官网在这个位置,点击左下角下载Android Studio 官网:www.Android.com 中国大陆版网站::https://developer.android.google.cn/ 2、Android Studio会自带自动下载Android SDK,如果有版本…

SIM8100、SIM8800CE、SIM8800E 车规级模组 特性

1、SIM8100 是一个C-V2X模块,通过PC5接口支持C-V2X功能,实现车对车(V2V)、车对人(V2P)、车对基础设施(V2I)等应用。 SIM8100具有强大的扩展能力和丰富的接口,包括USB, UART, SDIO,I2C,I2S,SPI, GPIO等。 该模块为客户的应用程序提供了很大的灵…

Vue--》动态组件和插槽的使用讲解

目录 动态组件 keep-alive使用 keep-alive的include和exclude属性 插槽 动态组件 动态组件指的是动态切换组件的显示与隐藏&#xff0c;vue提供了一个内置的<component>组件&#xff0c;专门用来实现动态组件的渲染。什么意思呢&#xff1f;接着往下看&#xff1a; …

类和对象之 封装 继承 与 多态

1.进行类继承的前提是我们要有两个类&#xff0c;且已经确定好了这两个类谁为父类谁为子类 2.先创建父类然后再创建子类 3.创建子类的时候我们要使用继承语法&#xff0c;使用的方式是在创建子类时的第一条代码的最后面加上冒号 : 和父类的类名 4.继承的本质就是将父类中的…

[附源码]Python计算机毕业设计Django药品仓库及预警管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…