GATT 综述 , 是一个服务框架
程序
发现, 读, 写, notify, indicating, 配置特性的广播.
服务和其特性
依赖
app 依赖 GATT , GATT 依赖 GAP
程序
There are 11 features defined in the GATT Profile:
1. Server Configuration
2. Primary Service Discovery
3. Relationship Discovery
4. Characteristic Discovery
5. Characteristic Descriptor Discovery
6. Reading a Characteristic Value
7. Writing a Characteristic Value
8. Notification of a Characteristic Value
9. Indication of a Characteristic Value
10. Reading a Characteristic Descriptor
11. Writing a Characteristic Descriptor
profile service character descriptors 的关系
GATT中最上层是Profile,Profile由一个或多个服务( Service) 组成
服务(Services)、特性(Characteristics)和描述符(Descriptors)都是属性类别,因此也就有了通用属性配置文件(Generic Attribute Profile)、属性表(Attribute Table)和属性协议(Attribute Protocol)等。
具体是哪一个类别的属性,由“通用唯一标识符(Universally Unique Identifier,简称UUID)”来定义。
服务(Service)、特性(Characteristics)和描述符(Descriptors)也有层级之分。
服务包括一项或多项特性。
一项特性可能没有、拥有一个或拥有多个描述符
规定数据按照一定规则存放,这个规则就是属性。
属性句柄( 2 个字节) + 属性类型( 2 个字节) + 属性值( 0 - 512 个字节) + 属性权限
1. 属性句柄( Attribute Handle)
通过他可以找到对应属性,并用于区分不同服务中的相同属性。我理解类似是数组下标。
2. 属性类型( Attribute Type)
是对某个东西取一个数字代号( 用uuid来代号) ,比如心率计,SIG就是用0x180D 这个uuid来表示这个这条属性是和心率计有关SIG将uuid进行了范围规定,下面这些uuid都来标识属性类型
0x1800 ~ 0x26FF 用于服务类 UUID
0x2700 ~ 0x27FF 用于标识计量单位
0x2800 ~ 0x28FF 用于区分属性类型
0x2900 ~ 0x29FF 用于特性描述
0x2A00 ~ 0x7FFF 用于区分特性类型
3. 属性值( Attribute Value)
属性值是一个 0 ~ 512 字节的数据,属性值是给上层应用层使用的,是用户“真正”要使用的数据,属性值可以有一下几类
服务通用唯一识别码( UUID)
单位
属性类型
特性描述符
特性类型
属性句柄 是不用填充的
属性类型 需要填充
一般包括
uuid
权限 ( 读写 notify initicate)
长度
属性值
如果是特性声明, 需要填充属性值 描述符 ( 包括访问控制权限( 读) , 特征数值句柄, 特征数值uuid )
Service Definition 部分
Service Declaration
Include Definitions ( >= 0 )
Characteristic Definitions ( >= 0 )
Characteristic Definitions 部分
- Characteristic Declaration : First
- Characteristic Value declaration : Second
- Characteristic Descriptor Declarations ( Optional) ( >= 0 ) : Last ( 含多个时顺序不关紧要)
Characteristic Descriptor Declarations ( Optional) ( >= 0 ) 部分
- Characteristic Extended Properties
- Characteristic User Description
- Client Characteristic Configuration
- Server Characteristic Configuration
- Characteristic Presentation Format
- Characteristic Aggregate Format
Attribute Type UUID Description
< Primary Service> 0x2800 Primary Service Declaration
< Secondary Service> 0x2801 Secondary Service Declaration
< Include> 0x2802 Include Declaration
< Characteristic> 0x2803 Characteristic Declaration
< Characteristic Extended Properties> 0x2900 Characteristic Extended Properties
< Characteristic User Description> 0x2901 Characteristic User Description Descriptor
< Client Characteristic Configuration> 0x2902 Client Characteristic Configuration Descriptor
< Server Characteristic Configuration> 0x2903 Server Characteristic Configuration Descriptor
< Characteristic Format> 0x2904 Characteristic Format Descriptor
< Characteristic Aggregate Format> 0x2905 Characteristic Aggregate Format Descriptor
Attribute 实例,从app看
属性句柄( Attribute Handle) 属性类型( Attribute Type) 属性值( Attribute Value) 属性许可( Attribute Permissions)
service: 无 0x2800 ( 用于区分服务类型, 首要服务) 0x1800 ( 服务通用唯一识别码, GAP)
service: 无 0x2800 ( 用于区分服务类型, 首要服务) 0x1801 ( 服务通用唯一识别码, GATT)
character: 无 0x2A00 ( 用于区分特性类型, Device Name) "Apple Watch" ( 特性类型, Device Name 的 value)
character: 无 0x2A05 ( 用于区分特性类型, Service Changed) 自定义
character: 无 0xXXXX ( 自己建立的uuid) ( 用于区分特性类型, Unknow Service) 自定义
Descriptors: 无 0x2902 ( 用于区分描述类型, Client Characteristic Configuration, 可以通过这个Descriptors 来 notify和 indicate) "Notifications and indications disabled" ( 特性类型, enable 或者 disable)
Descriptors: 无 0x2900 ( 用于区分描述类型, Characteristic Extended Properties, 可以根据这个 Descriptors 来 在 notify 和 indicate 的同时实现 write) "Reliable Write enabled"
Descriptors: 无 0x2901 ( 用于区分描述类型, Characteristic User Description) "Telink SPP:module->phone"
标准 service
1800 Generic Access
标准 characcter
2 A00 Device Name
2 A01 Appearance
标准 service
1801 Generic Access
标准 characcter
2 A05 Service Changed
标准 service
180F Battery Service
标准 characcter
2 A19 Battery Level
标准 service
1805 Current Time Service
标准 characcter
2 A2B Current Time
2 A0F Local Time information
标准 service
180 A Device Information
标准 characcter
2 A29 Manufacturer Name String
2 A24 Model Number String
character 与 service 的实例 (开发中应该新建几个service?)
profile 描述一个或多个设备,在每个设备上有一个或多个服务的规格。
可以看到他可以包含多个 Service,大部分 Service 其实都是 BLE 本身自带的,一般都是 SDK 定义好了的,我们不需要修改和操作的,我们要用的 Service 可能一个工程里面只有一个。
举个例子:一个血压计设备,他可能只有一个我们需要操作、修改的 Service,就是读取血压数值然后发送给 APP。
再举个例子:一个带心率功能的计步器,有两个功能,一个是计步,还有一个是测量心率,那么这个设备可能就有两个 Service 需要我们操作、修改。
这些新增的服务都属于 profile .
在图中还能看到一个 Service 可能包含多个 Characteristic,这就是一个服务所包含的特征值。怎么理解特征值呢,还举那个血压计的例子吧:
上面说过血压计只有一个 Service ( 代表他只有这个服务的一系列值) ,就是读取血压数值然后发送给 APP,但是这一个 Service ( 一般一个值对应一个charatcer) 可能包含多个 Characteristic
也就是说一个血压计的设备有一个服务,一个服务就是一个功能,但是这个功能可能包含了好几个变量,这个 Characteristic 可以暂时理解为变量。所以说 BLE 之间的数据交换是通过 Characteristic 做到的。
具体怎么定义 Characteristic 要 根据 需求来定
特性包括多个部分,如类型、值、一些属性和权限等。
特性一般包括三个要素:声明、数值和描述。
前两者都是必须的。
作为通信交互,一个特性必须要告诉对方声明(存储长度和访问控制)、定义(具体赋值)。
在某些特性(如notify或者indicate)里面,特性还需要告知对方附加的配置属性(提供订阅等)。
特性声明必须作为服务属性之后的第一条属性,而数值必须紧随其后。
无论是服务还是特性,它们都是一条条属性;
特性的各个要素也是一条条属性。
只不过,不同的服务是独立的;而一个服务如果有多个特性,那么不同的特性也是独立的;一个特性包含的多条属性则是关联的。
类型(Type)
在上面已经解释过了,就是表明属性具体特性类别的UUID值
uuid 由 Handle、UUID(属性类型)、Value(属性值) 组成.
这张图由三个部分组成,分别是 Handle、UUID(属性类型)、Value(属性值)。我们先来说 UUID,UUID 是通用唯一识别码。这里表示的是属性类型。举个例子,在 BLE 协议中定义了 0x2800 这个 UUID,它代表了一个这个属性的类型是 Service;0x2803 这个 UUID,表示这个属性的类型是一个 Characteristic。
那我们看到 UUID 有很多都重复出现了,那怎么区别他们呢?那就要靠前面的 Handle 了,这个 Handle 是不能重复的,就是一个属性在属性列表中的位置,所以可以当做地址来理解。两个属性的 UUID 可能是相同的,但是 Handle 永远不可能相同。
值(Value)
就是相关状态数据项的值。
属性(Properties)
属性定义了其他设备如何通过蓝牙运用特性,这些特性主要关于各项操作,如读取(READ)、 写入(WRITE)或通知(NOTIFY)。
读取特性就是通过蓝牙链路将当前的值从属性表传输至相连的设备。
写入是允许互连设备改变状态表中的值。
通知是当相关特性值改变或由定时器进行周期性控制时,设备可以发送至相连设备的
一种特定的信息类型。有些特性并不支持所有操作。通过特性的属性可以了解其支持的操作。
有时设备的编程允许其在处理操作时(如在属性表中读写值)能够以特定的方式作出回应,这样就能实现更多功能,而不是简单的通过连接来传输数据。例如,改变特性的值也可能改变设备从加速器上读取样本数据的频率。
权限(Permissions)
权限与安全相关,并进一步描述了在对特性进行读写访问之前必须确保的安全条件。
描述符(DESCRIPTORS)
描述符含有元数据,这些元数据可以放大描述符所属特性的相关细节,或实现涉及这一 属性的运行配置。
例如,可通过名为“客户端特性配置描述符(Client Characteristic Configuration Descriptor,CCCD)”的特定描述符来开启或关闭通知(NOTIFY)信息。
配置文件(PROFILE)
蓝牙配置文件是包括所有必需信息的规格,包括设备功能,服务、属性及描述符的访问方式,以及安全准则、并行限制等。
对开发者来说,很简单,他只需要调用send ( 0x53 )
GATT层定义数据的类型和分组,方便起见,我们用0x0013 表示电量这种数据类型,这样GATT层把数据打包成130053 (小端模式!)
ATT层用来选择具体的通信命令,比如读/ 写/ notify/ indicate等,这里选择notify命令0x1B ,这样数据包变成了:1 B130053
nrf connect app
nrf connect
下箭头按下 : 读
上箭头按下 : 写
上下箭头此时状态 : notify and indication 关闭
上下箭头打叉此时状态 : indication 开
三下箭头此时状态 : notify and indication 关
三下箭头打叉此时状态 : notify enable 开
notification无需client端确认,就好像小明妈妈跟小明发了一条信息说该吃饭了,小明收到了可以有动作也可以忽略。
indication是需要client端确认,举个例子小明妈妈跟小明打电话,小明务必点击接听,听妈妈跟他说该吃饭了,整个过程才完结。
当 notify 或者 indication 为开的情况下, 当value 改变( 通过定时器, 通过host端主动修改) , ble 会主动上报改变过的 value.
标准服务
可以通过GATT层定义自己的Profile
1800 和1801 服务UUID为TI蓝牙协议栈的GATT层服务。
GATT Services
GATT Characteristics
UUID
#define GAP_SERVICE_UUID 0x00001800
#define GATT_SERVICE_UUID 0x00001801
#define DEVICE_NAME_UUID 0x00002A00
#define APPEARANCE_UUID 0x00002A01
#define PERI_PRIVACY_FLAG_UUID 0x00002A02
#define PECONNECT_ADDR_UUID 0x00002A03
#define PERI_CONN_PARAM_UUID 0x00002A04
#define SERVICE_CHANGED_UUID 0x00002A05