2、蓝牙核心协议栈回顾:HCI层、L2CAP层、RFCOMM层、GATT层在多点连接中的作用

好,咱们直接进入正题。

做蓝牙多点连接,你绕不开协议栈。说白了,这四层就是蓝牙的「四根柱子」。我当年刚接触多点连接时,总觉得协议栈是理论课,结果调试时被HCI的Event队列坑了一整天——嗯,从那以后我再也不敢小看任何一层了。

2.1 HCI层:主机与控制器的「翻译官」

HCI,全称Host Controller Interface。它的作用很简单:让芯片的Host(你的应用处理器)和Controller(蓝牙射频芯片)能对话。

在多点连接中,HCI层负责什么?

  • 连接管理:创建、断开、切换ACL链路。你同时连手机和耳机,HCI层要维护两条独立的ACL链路。
  • 事件通知:连接建立、断开、角色切换等事件,都通过HCI Event上报。我遇到过一个问题:两个设备同时断开,Event队列乱序,导致状态机崩了。后来加了Event序列号校验才解决。
  • 数据收发:ACL数据包通过HCI Data通道传输。多点连接时,数据包要带上Connection Handle,否则不知道发给谁。

关键点:HCI层不关心数据内容,只关心链路状态。它就像快递员,只负责把包裹送到正确的地址,不管包裹里装的是书还是衣服。

我的经验:调试多点连接时,先抓HCI Log。看Connection Handle是否正确,Event是否按预期触发。我曾经花了两小时查应用层bug,最后发现是HCI层链路ID分配错了。

2.2 L2CAP层:数据分片与通道复用

L2CAP,Logical Link Control and Adaptation Protocol。名字很长,但核心功能就两个:分片重组通道复用

在多点连接中,L2CAP层的作用:

  • MTU协商:每个连接独立协商MTU。你连手机(可能支持672字节)和连耳机(可能支持48字节),L2CAP要分别处理。
  • 通道标识:每个L2CAP通道有唯一的CID。多点连接时,不同设备的不同服务(如A2DP、HFP)使用不同的CID。
  • 分段与重组:上层数据太大时,L2CAP会切成小段发送。接收端再拼回去。我见过一个坑:两个设备同时发大包,重组缓冲区溢出。后来限制了并发大包数量才稳定。
场景 L2CAP行为
手机A发送A2DP音频 使用CID 0x0040,MTU 672
耳机B发送HFP语音 使用CID 0x0041,MTU 48
同时收发 L2CAP根据CID区分数据流

注意:L2CAP层不保证顺序。如果你依赖数据顺序,需要在应用层加序列号。我早期做项目时没注意这点,音频和命令数据乱序,导致耳机播放了错误的提示音。

2.3 RFCOMM层:串口仿真的「老黄牛」

RFCOMM,Radio Frequency Communication。它模拟串口通信,很多经典蓝牙服务(如SPP、HFP、PBAP)都跑在它上面。

在多点连接中,RFCOMM层的作用:

  • 多路串口:一个物理链路可以虚拟出多个串口。你同时连手机A(HFP)和手机B(SPP),RFCOMM会分配不同的DLCI(数据链路连接标识符)。
  • 流控:每个虚拟串口独立做流控。一个设备发数据太快,不会影响另一个设备。
  • 帧格式:RFCOMM有自己的帧头,包含地址、控制、长度等信息。我调试时经常用逻辑分析仪看RFCOMM帧,确认DLCI是否正确。

避坑指南:我曾经遇到一个问题——两个设备同时建立RFCOMM连接,第二个连接总是失败。查了半天,发现是RFCOMM的MSC(调制解调器状态命令)处理有竞态条件。解决方案是加一个互斥锁,确保MSC命令串行执行。

2.4 GATT层:属性协议的「新贵」

GATT,Generic Attribute Profile。它是BLE的核心,但经典蓝牙也在用(通过BR/EDR传输)。

在多点连接中,GATT层的作用:

  • 服务发现:每个连接独立发现服务。你连手机A(支持心率服务)和手机B(支持电量服务),GATT会分别维护服务列表。
  • 属性读写:每个连接有独立的ATT Bearer。一个连接在读写属性,不会阻塞另一个连接。
  • 通知/指示:多点连接时,通知要带上Connection Handle。否则你不知道这个通知该发给谁。

我的习惯:在GATT层,我会为每个连接维护一个独立的属性缓存。这样切换连接时,不需要重新发现服务。但要注意缓存一致性——设备更新了服务,缓存要失效。

2.5 四层协作:一个多点连接的典型流程

咱们看一个实际场景:耳机同时连接手机A和手机B。

  1. HCI层:建立两条ACL链路,分配Connection Handle 0x001和0x002。
  2. L2CAP层:为每个连接创建L2CAP通道。手机A的A2DP用CID 0x0040,手机B的HFP用CID 0x0041。
  3. RFCOMM层:在手机B的HFP通道上,建立RFCOMM会话,分配DLCI 0x02。
  4. GATT层:如果手机A支持BLE,再建立GATT连接,用于传输电池电量等信息。

你看,每一层各司其职。HCI管链路,L2CAP管通道,RFCOMM管串口,GATT管属性。少了任何一层,多点连接都跑不起来。

总结一下

  • HCI层:链路级的多点,负责连接建立和断开。
  • L2CAP层:通道级的多点,负责数据分流和MTU管理。
  • RFCOMM层:串口级的多点,负责虚拟串口和流控。
  • GATT层:属性级的多点,负责服务发现和属性读写。

下一章,咱们会深入HCI层,看看多点连接时如何管理多条ACL链路。到时候我会分享一个我踩过的坑——关于HCI Command超时处理的。嗯,先卖个关子。