BLE协议栈学习_L2CAP_ATT_GATT_In-depth Understanding of the Bluetooth Protocol Stack
目录
L2CAP
信道
- 信道是指的L2CAP逻辑通道,和物理信道不同指的是一个数据包序列,连接两个设备上的一对服务,两个设备间允许同时使用多条信道
- 信道作用:通过CID区分数据是来自哪个上层协议,使得数据不互相干扰
- BLE只支持固定信道,固定信道指的是两个设备一建立连接就已经存在的、没有任何配置参数的信道
- 信道标识符:16位数字
- BLE使用了3条信道:
- 0x0004 属性协议
- 0x0005 低功耗信令通道
- 0x0006 安全管理协议
数据包结构

- 32bits的报头,包含2bytes长度和2bytes信道标识符
- 长度表示信息载荷的字节数,其MTU最大为63353,注意和ATT_MTU 区分
信令信道
- 用于主机层的信令
- 命令操作码:
- 命令拒绝
- 连接参数更新请求
- 连接参数更新响应
命令拒绝
- 拒绝设备收到的不支持的信息报
连接参数更新请求和响应
- 让从设备更新链路层的连接参数,仅用于从设备向主设备发送更新请求,主设备响应,主设备要更新连接参数直接从链路层更新
只有理解属性协议才能理解BLE
ATT&GATT
- 提供数据的设备称为服务器,使用其他设备数据的称为客户端
- 服务器是一个持有许多状态信息的设备,客户端是读写该状态信息或者在本地缓存为数据的设备
- 状态是指:静态的,例如设备名称、序列号、硬件版本等,这些值通常在设备生命周期内不变。动态的,例如传感器读数、电池电量、连接状态、配置开关等,它们会随设备运行而变化。
属性
- 属性由属性句柄、属性类型、属性值组成
![image]()
属性句柄
- 有效句柄范围:0x0001~0xFFFF
主机端通过UUID发现特征,通过属性句柄来读写特征
属性类型
- 公开的数据种类为属性类型
- 由于数据类型较多,使用128位32字节的数字来标志属性类型,这个标识码叫通用唯一识别码(UUID)
- 为提高传输效率,,定义了一个蓝牙UUID基数的通用识别码,结合一个16位的数使用,服务器发送16位数据,客户端收到后补上UUID基数
| 基数UUID | 00000000-0000-1000-8000-00805F9B34FB |
|---|---|
| 完整UUID | 0000XXXX-0000-1000-8000-00805F9B34FB |
- UUID并没有定义自身的用法,为了增加调试可读性,UUID分为一下几组
| UUID范围 | 作用 |
|---|---|
| 0x1800~0x26FF | 服务类通用唯一识别码 |
| 0x2700~0x27FF | 计量单位 |
| 0x2800~0x28FF | 区分属性类型 |
| 0x2900~0x29FF | 特性描述 |
| 0x2A00~0x7FFF | 特性类型 |
属性值
- 用于表示设备公开信息,范围0~512字节
UUID
- 每种服务都可以通过UUID来区分
计量单位
- 传感器计量单位
属性类型
- 首要服务
- 次要服务
- 包含
- 特性
特征描述符
- 服务公开的数据包含了额外的信息,额外的信息就是特征描述符,如描述数值的单位就是描述符
特征类型
- 特征类型:服务为公开的每一类数值分配了特征类型UUID
属性许可
- 使用许可、认证许可、授权许可
- 属性许可只能用于属性值,不能用于属性句柄和属性类型
使用许可
- 客户端读取属性时首先检查使用许可,判断属性值是否可读,写入同理
认证许可
-
每当使用一种属性时,无论读写都要验证其认证许可,如果需要认证,客户端发起认证请求,只有通过认证的客户端才能访问需要认证的属性
-
认证和加密:安全级别不一样,加密是空中加密,无法防止中间人攻击
接入属性
客户端通过一下消息类型访问属性数据库总中各个属性:
- 寻找请求:寻找属性数据库中的属性
- 读取请求:读取属性值,要指定属性句柄或句柄范围
- 写入请求:指定属性句柄和要写入的数
任意请求都会使得服务器发送响应,客户端一次只能发起一条请求,收到响应后才能发送下一条请求 - 写入命令:写入命令不要求服务器回复,可以任意时刻发送
- 通知、指示:由服务器主动向客户端发送属性值,通知可以任意时刻发送,指示需要客户端回传确认信息
原子操作和事务
- 客户端和服务端之家按每一条属性协议的信息都属于某个事务的一部分,事务可以是一条请求及其响应,或一条指示或确认信息,一个事务结束之前不能发起新的事务
- 原子操作:要么全部执行,要么全不执行
命令和通知
- 命令和通知的发送无需等待响应,可以随时发送
- 命令和通知无法确认对方是否接收到
准备写入请求和执行写入请求
- 准备写入请求时将一段数据暂存服务器缓冲区,不立即执行写入,服务器会保存这些数据片段以及对应的属性句柄和偏移量,并返回一个准备写入响应,这个特性使得设备可以多次发送,每个请求针对同一属性或不同属性,按偏移量累积数据
- 执行写入请求指示服务器将所有暂存的准备写入数据一次性应用到对应的属性上,或者取消这些暂存数据
- 长写入:长写入是 GATT 层的一种过程,用于写入超过单个 ATT 写入请求所能携带的最大数据量(受限于 MTU)的数据,普通写入请求写入最大长度为ATT_MTU-3,如果要超过这段写入长度,需要使用长写入功能,该方式用于固件升级
- 长写入和多次写入的区别在于:长写入要数据完整后才执行一次,多次写入每写入一次就生效,数据会存在中间态
- 校验写入:24位CRC校验可检测5位错误,加密包中有32位消息完整性检查MIC值
属性分组
- 服务和特性都使用了分组,使用服务声明来对服务进行分组,使用特征说明来对特征进行分组
- 服务是一种或多种特征的组合,特征由一种或多种属性组成
服务
扩展服务
- 服务A可以包含服务B,实现服务B的扩展,实现对旧设备的兼容
引用服务
- 服务A引用服务B
首要服务和次要服务
- 首要服务通常是公开设备功能的服务,首要服务可以指向首要服务,大多数服务都是首要服务
- 次要服务只能通过引用来发现,必须通过另一个服务来指向次要服务
- 当客户端寻找某特定服务是可以快速找到首要服务
服务声明
- 使用服务声明对服务进行归类
- 服务声明的值是服务的UUID,可以是16位或128位
特征
- 特征包含特征声明/数值/描述符
特征声明
- 特征声明包含性质、数值句柄、属性UUID
- 特征性质确定特征数值对读写/通知/指示等操作的支持情况
- 特征数值句柄包含特征数值属性的句柄,客户端返回特征声明给服务器,服务器通过特征数值句柄获取属性数值
- 特征UUID识别特征数值的类型
特征数值
特征描述符
- 一个特征可以包含多个描述符,描述符是可选的
- 特征扩展性质描述符
- 特征用户描述描述符
- 客户端特征配置描述符CCCD:支持通知或指示的特征必须使用客户端特征配置描述符
- 服务器特征配置描述符SCCD
- 特征聚合格式描述符
属性协议
请求/响应/命令/指示/确认
- 客户端通过向服务器发送请求,要求服务器执行相关操作并响应,客户端一次只能发送一条请求,请求有两种响应:与请求直接相关的响应,或是请求失败的错误响应
- 客户端发送命令但是不一定收到响应
- 服务器通过向客户端发送指示,让客户端获取属性值,指示需要确认响应
- 服务器发送通知告知属性数值,不要求响应
- 如果命令和通知过多,接收端可以忽略
GATT通用属性规范
- 属性协议定义了客户端与服务器如何相互发送符合标准的消息,GATT定义了如何发现与使用服务、特性与描述符的标准方法
发现规程
- 客户端首先发现首要服务,隶属于首要服务信息都可以被发现,随后客户端为每个首要服务设置句柄范围,以发现次要服务
发现服务
- 客户端可以使用按组类型读取请求,请求句柄范围为0x001:0xFFFF,属性类型为首要服务,客户端发现设备公开的所有首要服务来判断设备功能
- 客户端如过只想使用某个服务而不想使用其他服务,可以按类型值查找服务,把类型设置为首要服务并把数值设为需要获取的已知服务类型,服务器将响应响应服务的句柄范围
特征发现
- 发现服务的所有特征:为发现特征,按类型读取请求,将句柄范围设置为该服务的句柄范围,并把类型设置为特征,这样能发现所有特征声明
- 请求发出后响应中包含服务中每一个特征的声明和句柄
- 发现所有特征描述符:发现特征声明后就可以发现特征描述符
客户端对特征的操作
-
读取特征值
-
一旦发现特征描述符,特征值便能够通过读取请求读取
-
读取请求与大对象读取请求:属性长度固定且小于MTU时可以使用读取请求读取,大于MTU时,使用一条读取请求读取特征值开头22字节,随后用一个或多个大对象读取请求来获取特征值剩余部分
-
使用特征UUID读取:只读取某个特征值,不使用服务上所有特征声明再读取该值
-
同时读取多个特征值:已知每个特征值句柄,每一个值的长度,可以同时读取多个特征值
-
-
写入特征值
- 属性协议的操作是原子的,如果长属性的写入需要多个请求,可能使得属性值的一部分发送变化,因此有了长写入来保证原子性,使用之前的准备写入请求和写入请求来实现
- 特征值可靠写入在长写入基础上增加了一个校验
- 无响应写入:快速写入,不需要协议层面回复,
-
读取/写入特征描述符
- 与特征值的读写基本一致
通知/指示
- 通知时由服务器发起,可以在任意时刻发送给客户端,属于不可靠消息
- 指示由服务器发起,需要在接收到上条指示的确认信息后才能发新的指示


浙公网安备 33010602011771号