发表于 2025-3-28 17:40:00

从0开始学习BLE:获取服务、特征

通过以前的学习,我们了解到BLE设备作为服务端,存储着一些数据,客户端就是通过读写和配置这些数据来实现相应的功能的。
前面我们了解了广播、连接,今天来看看连接后发生了什么事情服务和特征的发现过程设备建立连接后,首先会获取服务列表

数据包结构:


来看下实际数据包

访问地址后面跟随的是数据包头


LLID:这个数据位表明了包所属的逻辑链接,以及有效数据部分是否包含链路层数据包或者链路层控制包。其中:
00 表示为保留。
01表示为链路层数据PDU,且L2CAP消息是连续分段或空的PDU。
10 表示为链路层数据PDU,且L2CAP消息的起始或未分段的完整I2CAP消息。(当前我们的数据就是这个包头)
11表示为链路层控制包。

空包的LLID
NESN:接收方通过 NESN 告知发送方自己期望接收的下一个数据包的 SN。接收方成功接收一个数据包后,将 NESN 翻转。
发送方根据接收到的 NESN 判断是否需要重传:
[*]如果 NESN == 当前发送的 SN:表示接收方已正确接收,发送下一个新数据包。
如果 NESN != 当前发送的 SN:表示接收方未收到,需要重传。
SN:数据包序列号:用于标识当前数据包的顺序,确保接收方可以检测丢失或重复的数据包。
每发送一个新的 非空数据包(包含有效载荷),SN 会翻转。如果重传相同的数据包,SN 保持不变。接收方通过对比当前 SN 和上一次收到的 SN,判断数据包是 新数据 还是 重传。
所以我们抓到的数据如下

可通过 Wireshark 观察这两个字段排查丢包或重传问题。MD:(More Data)标志位 用于指示当前设备是否还有更多数据需要传输,发送第一个数据包时设置 MD=1,表示还有后续数据。主机收到后,继续监听(不终止连接事件)。

我们这里没有更多数据
RFU:保留
长度:我们的数据是有效载荷长度11个字节

信道标识符CID=0x0004,表面剩下的数据内容归ATT即属性协议管



ATT层的数据结构如下

属性PDU
0x10操作码对应的是按组读取属性

操作码

按组访问属性按组类型读取请求用于获取属性类型已知、分组属性类型由上层规范定义但句柄未知的属性值。常见的属性类型 UUID(即 GATT 规定的 UUID 句柄)包括:
主要服务(Primary Service):UUID: 0x2800
次要服务(Secondary Service):UUID: 0x2801

查询句柄从0x0001开始到0xffff的0x2800服务,代表查询所有的主要服务
从设备传回了相应的数据

属性查询应答

按组类型读取请求响应

操作码0x11:属性查询应答起始句柄0x0001,结束句柄0x0009,属于GAP服务(UUID=0x1800)起始句柄0x000a,结束句柄0x000a,属于GATT服务(UUID=0x1801)接着主机又发送一个按组查询

再次查询
123/gvntyx3vpec6404011808.png
第二次查询应答0x000b到0xffff的句柄属于自定义的主要服务,在这个例子中,我们是自定义的一个控制LED灯的服务。然后,主机发送一个请求属性的数据包
123/b24ddkugy3h6404011908.png
123/nqjlwb04kod6404012008.png
读取0x000b的属性还记得我们之前说过,每行数据就是一条属性
123/xssf1uytj3n6404012108.png
属性的构成对于服务来说,读取的是服务的类型(UUID)然后从机给出应答,返回服务的UUID
123/wlstyrzb5tj6404012208.png
然后,主机又发送一条0x08操作码:按类型读取请求。在句柄范围中获取属性类型已知但句柄未知的属性值。
123/raomwsrvxyl6404012308.png
123/xyyveleggyj6404012408.png
123/ztrvkvlxewa6404012508.png
按类型读取请求0x2803:特征声明。此条数据要求读取0x0001~0x0009范围内的特征声明。从机返回数据如下:
123/bflzs0r4jy46404012608.png
特征声明响应之前我们说过,一条特征包含3个属性,分别是:特征声明,特征值,特征描述符。特性声明:特征声明的属性类型(UUID)是0x2803,准确来说是0x2803表示这是一条特性声明,整个特性的开始。
123/zcpwsy40hlj6404012708.png
特性属性:示客户端可以对特性执行的操作。常见的属性值包括:
123/dtivusqlung6404012808.png
特性值的属性句柄和特性值的UUID就是指下一行的属性句柄和UUID。从机返回3个特征声明:分别是设备名称,设备外观,和首选连接参数
123/nknajf5xmpi6404012908.png
123/2dkipmlqml46404013009.png
[*]BLE 4.x 默认 ATT MTU 为 23 字节,扣除头部后,实际可传输的特性声明数据有限。每个特性声明占 7 字节(Handle 2 + Properties 1 + Value Handle 2 + UUID 2),因此单包最多返回:

123/epcjsfjy3td6404013109.png
BLE 5.0+ 支持扩展 MTU(如 247 字节),可一次性返回更多特性。

然后,主机获取剩余的特征声明
123/0rqhtdv40up6404013209.png
再次获取特征声明
123/42pahnvxo456404013309.png
特征声明响应中央地址解析(Central Address Resolution)是蓝牙规范中的一个特性,它允许设备在连接期间解析随机私有地址。当设备支持此功能时,它可以识别之前配对过的设备,即使该设备使用了随机地址。同伙获取特征声明知道了保护哪些特征,也知道了对应的句柄
123/uhufzths5nz6404013409.png
获取特征值通过获取特征声明知道了如下信息
123/01g1mayjkou6404013509.png
通过0x0A操作码分别读取0x0003,0x0006的属性值,获取设备名字和外观。通过0x0007句柄获取连接参数。
123/xhdh4ez5bbx6404013609.png
连接参数包含最小连接间隔和最大连接间隔。除了分步查询,主机还使用了0x04操作码:信息查找,一次性获取全部特征列表
123/3brbgxhcw0m6404013709.png
从机分多个包连续返回特征列表
123/3kzgdxnfjqk6404013809.png
主机还发送了一个起始句柄小于结束句柄的查询,获得了一个错误的响应,不知道为什么主机要这么发,难道确保不会没有获取到的信息?总之经过上面一系列操作,最终我们得到了如下界面的内容
123/yv40xe00cjn6404013909.png
以上就是GAP层、ATT层、L2CAP层干的那些事。上述通信过程,对从机来说是由协议栈GAP层和ATT层及L2CAP层来实现的,所以不用过于担心实现问题,你只要准备相应的数据即可。
页: [1]
查看完整版本: 从0开始学习BLE:获取服务、特征