第2章:蓝牙协议栈架构:Host与Controller的划分、HCI接口的作用、L2CAP层详解、RFCOMM协议、SDP服务发现协议

好,咱们直接切入正题。蓝牙协议栈,说白了就是一套通信规则的总和。很多初学者一上来就被那几十层协议吓住了,其实没那么复杂。我个人习惯把蓝牙协议栈想象成一个「快递系统」——有分拣中心、有运输车队、有配送员。今天这一章,咱们就把这个系统的骨架搭起来。

2.1 Host与Controller的划分:谁负责动脑,谁负责动手?

蓝牙协议栈最核心的分界线,就是HostController。你想想看,一个蓝牙设备既要处理复杂的逻辑,又要实时收发无线信号,如果全揉在一起,代码维护起来简直是噩梦。

Controller,通常是一个独立的芯片(比如CSR、TI的CC系列),它负责最底层的活儿:

  • 射频收发、跳频、调制解调
  • 基带处理、链路控制
  • 物理层的时序控制

Host,则跑在主处理器上(比如你的手机AP、Linux主机),它负责:

  • 逻辑链路控制(L2CAP)
  • 服务发现(SDP)
  • 应用层协议(RFCOMM、ATT等)
  • Profile的管理

关键点:Host和Controller可以跑在同一个芯片上,也可以分开。比如经典的蓝牙耳机方案,Controller是独立的蓝牙芯片,Host跑在耳机的主控MCU上。而像一些低成本的蓝牙模块,两者就集成在一起了。

我在项目中遇到过一种情况:某款智能手表,Host和Controller跑在不同的核上,结果因为HCI通信的延迟没处理好,导致音频断断续续。嗯,这里要注意——Host和Controller的划分,不仅仅是逻辑上的,更是物理上的性能权衡

2.2 HCI接口的作用:Host和Controller之间的「翻译官」

Host和Controller之间怎么通信?靠的就是HCI(Host Controller Interface)。说白了,HCI就是一套标准化的命令和事件格式。

HCI支持三种物理传输方式:

传输方式 典型场景 特点
UART 经典蓝牙模块(如HC-05) 简单、低成本、速度一般
USB PC蓝牙适配器 高速、即插即用
SDIO 嵌入式WiFi+蓝牙 combo芯片 高带宽、适合大数据量

HCI的数据包分为四种类型:

  • 命令包:Host发给Controller,比如「开始扫描」
  • 事件包:Controller回复Host,比如「扫描到设备了」
  • 数据包:ACL数据(普通数据)和SCO数据(音频数据)
  • 同步数据包:用于语音等实时流

避坑指南:我曾经调试过一个项目,蓝牙一直连不上。查了两天,最后发现是HCI命令包的参数长度填错了。HCI命令的格式非常严格,多一个字节或少一个字节,Controller直接不认。所以写HCI驱动时,一定要对照Spec逐字节核对

2.3 L2CAP层详解:蓝牙的「数据管道」

L2CAP(Logical Link Control and Adaptation Protocol),名字很长,但作用很简单——把上层的数据切成合适大小的包,然后通过Controller发出去

L2CAP的核心功能有四个:

  1. 协议复用:多个上层协议(RFCOMM、SDP、ATT)共用同一条ACL链路,L2CAP通过CID(Channel Identifier)来区分。
  2. 分段与重组:上层发来的大包,L2CAP会切成MTU大小的段;接收端再拼回去。
  3. 流量控制:通过Credit机制,防止发送方太快把接收方撑爆。
  4. 错误重传:在BR/EDR中,L2CAP支持可选的重传模式。

你想想看,如果没有L2CAP,上层协议就得自己处理分包和复用,那得多乱?

MTU(最大传输单元)是L2CAP最重要的参数。经典蓝牙的默认MTU是672字节,但实际应用中,我建议根据你的数据量来调整。比如传音频流,MTU设大一点可以减少包数量;传控制命令,MTU设小一点可以降低延迟。

L2CAP的通信流程大致是这样的:

// 伪代码示例:L2CAP连接建立
1. Host发送L2CAP_Connection_Req (CID = 0x0040)
2. Controller回复L2CAP_Connection_Rsp (结果=成功, CID = 0x0041)
3. 双方协商MTU大小
4. 开始数据传输

我记得有一次,客户反映他们的蓝牙键盘偶尔会丢键。查到最后,发现是L2CAP层的Credit用完了,但发送方没有及时等待Credit更新。说白了,就是流量控制没做好。

2.4 RFCOMM协议:蓝牙上的「虚拟串口」

RFCOMM,全称是Radio Frequency Communication。它的设计初衷很朴素——让蓝牙能模拟串口通信。为什么需要这个?因为很多老设备(比如GPS模块、打印机)都是用串口通信的,RFCOMM让它们可以无缝迁移到蓝牙上。

RFCOMM基于L2CAP,它定义了一套帧格式,包括:

  • SABM/UA/DISC:链路建立和释放
  • UIH帧:携带数据,支持多路复用
  • 流控帧:控制数据发送节奏

RFCOMM支持最多30个虚拟串口(通道号从1到30)。每个虚拟串口对应一个应用,比如通道1给蓝牙键盘,通道2给蓝牙鼠标。

注意:RFCOMM本身不提供加密和认证。如果你传输敏感数据,必须在RFCOMM之上再加一层加密(比如通过SPP Profile的配置)。我曾经见过一个项目,用RFCOMM传支付数据,结果被中间人攻击了——嗯,那场面挺尴尬的。

RFCOMM的典型应用场景:

  • 蓝牙串口适配器(SPP Profile)
  • 蓝牙打印机
  • 蓝牙工业数据采集

2.5 SDP服务发现协议:蓝牙设备的「自我介绍」

两台蓝牙设备连接后,怎么知道对方支持什么服务?靠的就是SDP(Service Discovery Protocol)

SDP的工作方式很简单:

  1. 设备A广播自己的服务列表(比如「我支持耳机服务、文件传输服务」)
  2. 设备B发起SDP查询(比如「你支持耳机服务吗?」)
  3. 设备A返回服务属性(比如「支持,我的音频编码是SBC」)

SDP的核心数据结构是服务记录,包含:

属性 说明 示例值
ServiceClassIDList 服务类别 0x1108(Headset)
ProtocolDescriptorList 协议栈信息 L2CAP + RFCOMM
ServiceName 服务名称 "My Bluetooth Headset"

个人经验:调试SDP时,我最常用的工具是hcitoolsdptool。比如用sdptool browse XX:XX:XX:XX:XX:XX就能看到对方设备的所有服务。有一次我发现某个设备返回的服务记录里,协议描述符写错了,导致连接一直失败。所以,SDP的解析代码一定要写得健壮,因为不是所有设备都严格遵守规范

SDP还有一个特点:它是无连接的。也就是说,查询服务时临时建立L2CAP连接,查完就断开。这样设计是为了节省资源,毕竟服务发现只是连接前的「打招呼」环节。

小结

这一章咱们把蓝牙协议栈的骨架讲清楚了:

  • Host和Controller:分工明确,一个动脑一个动手
  • HCI:两者之间的通信桥梁,格式必须严格
  • L2CAP:数据管道,负责分包和复用
  • RFCOMM:虚拟串口,让老设备也能用蓝牙
  • SDP:服务发现,让设备互相认识

下一章,咱们会深入BLE协议栈,看看它和经典蓝牙有什么不同。嗯,到时候你会发现,BLE的架构更简洁,但坑也不少。

一句话总结:蓝牙协议栈就像一座大楼,Host是楼上的办公室,Controller是楼下的机房,HCI是电梯,L2CAP是走廊,RFCOMM是电话线,SDP是前台。理解了这些,你就掌握了蓝牙开发的「地图」。