写在前面:本文参考了 BLE4.0 低功耗蓝牙 协议 总结 ,对其进行了缩减,整理出了个人能理解的感觉比较基本的内容,
前面两篇请参考如下链接
BLE 4.0 协议知识点总结(一)
BLE 4.0 协议知识点总结(二)
BLE 4.0 协议知识点总结(三)
正文:
1、属性构成
GATT中的两个角色:服务器和客户端。
服务器:提供数据的蓝牙设备,例如手环。
客户端:需求数据的蓝牙设备,例如手机。
在L2CAP中可以看到(可参考BLE 4.0 协议知识点总结(三)),HOST通往下层的通道有三条,如果是应用的话只能通过(CID=0x0004)ATT属性协议往下传输的。属性的数据格式如下:
程序中存放的就是由多个上图属性格式存放的数据存放的数据库。它有四部分组成:属性句柄(Attribute Handle)、属性类型(Attribute Type)、属性值(Attribute Value)、属性许可(Attribute Permissions)。下图为采集到的空中心率计的一个数据表:
1.1属性句柄(Attribute Handle)
有两个字节组成,有效数据从0x0001~0xffff,0x0000保留不用。属性句柄的值在创建数据库时,按照递增的顺序创建的,但不一定是连续的,例如0x0003后面可以是0x0008。也没有规定属性句柄后面跟特定的属性类型(Attribute Type)和属性值(Attribute Value)。
属性句柄的作用是为了找到某个属性:举个例子,去超市存东西时,服务员会给你一个牌子,牌子上的号码跟你存放的东西是一一对应的,如果你要取东西时也要讲你的牌子给服务员,服务员根据牌子的号码来取出你存放的东西。属性存放到内存里,就相当于包存放到超市柜子里,会根据属性句柄的值来找出Attribute Type和Attribute Value。
1.2属性类型(Attribute Type)
属性类型其实就是给某个东西起个别名,让机器可以理解,所以属性类型给采用了2Bytes或者16Bytes的数字表示某个东西。例如,为了全球统一,心率计有个数字代号:0x180D,这个唯一的识别码叫做通用唯一识别码(Universally Unique Identifier(UUID)),在服务器的数据库中,只要找到服务是0x180D的值,就知道这是一个带有心率计服务功能的蓝牙设备。
2Bytes或者16Bytes的UUID:本来UUID是128bits的,为了提高传输效率,SIG规定了一个“蓝牙UUID基数”,作为128Bits的UUID,结合16Bits的UUID一起使用,发送方发送16Bits的UUID,接收方收到之后补上UUID基数即可。
蓝牙UUID基数:00000000-0000-1000-8000-00805F9B34FB
例如发送心率计服务UUID=180D,则完整的128Bits的UUID为:0000180D-0000-1000-8000-00805F9B34FB
对于低功耗蓝牙来讲,对UUID范围进行限制:
l 0x1800~0x26FF 用于服务类 UUID
l 0x2700~0x27FF 用于标识计量单位
l 0x2800~0x28FF 用于区分属性类型
l 0x2900~0x29FF 用于特性描述
l 0x2A00~0x7FFF 用于区分特性类型
1.3属性值(Attribute Value)
属性值是0~512Bytes的数据,属性值是给应用用的,属性值可以有如下类型:
UUID、单位、属性类型、特性描述符、特性类型。
1.4属性许可(Attribute Permissions)
属性许可是对属性值的一种保护,属性许可分三种类型:
(1) 、使用许可:可读、可写、可读且可写。读取属性值时,首先先判断这个属性值是否可读,如果不可读,服务器会返回给客户端一个不可读状态。写入属性值时,首先先判断这个属性是否可写,否则会收到属性值不可写状态信息。
(2) 、认证许可:需要认证、不需要认证。认证许可的意思是,是否允许客户端访问服务器。当客户端访问服务器的属性值时,如果需要认证,客户端会发出认证请求。当通过了认证之后,下次再访问需要认证的这个属性时,不需要再次认证。如果强行访问需要认证的属性值,会收到一个未认证的错误状态信息。
(3) 、授权许可:客户端有没有权利访问服务器的属性值。
2. GATT服务器构成
BLE 数据的库的组成如下:GATT Profile 分层
一个服务器中的数据库其实就是Profile,Profile由多个service组成,service由0个或多个include和至少一个characteristic 组成。
2.1 服务
服务是指一些列由数据或者相关行为组成的集合,去为了完成某个特定的功能或者特性。一个服务包含一个服务声明0个或多个包含定义以及至少一个特性定义。
服务定义的开始于服务声明,结束于下一个服务声明或者句柄达到0xFFFF。包含定义紧跟着服务声明,并在特性定义之前。特性定义紧跟着最后一个包含定义,如果没有包含定义,则紧跟在服务定义后面。
2.2 服务声明
简单说就是告诉其他设备可以提供什么服务,例如心率计,可以告诉设备可以提供心率计服务。
从上边心率计采集到的数据表格中可以看出,Attribute Handle 0x000C ~ 0x0011是一个心率服务,0x0012~0x0015代表一个电池服务。
服务声明如何定义呢?属性类型(Attribute Type)中UUID的某个特定的值就代表服务声明,这个特定的值就是0x2800,即由心率计服务中可以看出,Attribute Handle =0x000c对应的Attribute Type = 0x2800,则就会定义为服务声明,它声明一个心率计服务。即Attribute Type的这个UUID值是区分属性用的,实际上GATT Profile中属性类型有多个,如图所示:
首要服务和次要服务:
公开设备功能的服务成为首要服务。
次要服务不需要被其他设备知道,只能被首要服务引用,只能被首要服务的<Include>进行包含引用。
服务声明格式:
2.3 包含服务 Include
首要服务可以引用一个首要服务,也可以引用一个次要服务,次要服务。次要服务也可以引用一个次要服务或者首要服务,这种情况非常少。引用服务的格式入下:
可以看出,包含服务的Attribute Type 的UUID = 0x2802,Attribute Value部分有三部分组成:包含的服务的属性句柄,组结束标志,服务的UUID(可选)。
2.4 属性类型分组
上面有提到包含服务(Include)中包含有组结束的句柄,GATT Profile中将属性类型分为3组:首要服务(Primary Service)、次要服务(Second Service)、和特性(Characteristic)。一个组开始于一个声明,即服务分组结束于下一个服务声明,特性分组结束于下一个特性声明或者服务声明。也就是服务声明对服务进行分组,特性声明对特性进行分组。服务是一种或多种特性的组合,特性有一种或者多种属性组成。