第2章 蓝牙协议栈GATT层接口:HCI、L2CAP、ATT、GATT层级关系与API入口
在任何蓝牙GATT应用开发中,理解从控制器物理层到主机应用层的完整协议栈分层结构,是正确编写特征读写逻辑和定位数据流边界问题的基础。本章将剖析HCI、L2CAP、ATT和GATT四层的核心职责、层间封装关系,以及开发者直接接触的API入口和数据流控制点。
2.1 层级概述:主机(Host)与控制器(Controller)
蓝牙协议栈严格划分为两大逻辑区域:主机(Host) 和 控制器(Controller)。应用、GATT、ATT、L2CAP 以及 HCI 的上半部分(逻辑层)运行在主机侧;HCI 的下半部分(传输层)、链路层(LL)和物理层(PHY)属于控制器侧。开发者使用 GATT API 编写的代码全部在主机侧执行,而控制器负责空中的射频收发。
2.2 各层核心职责与对GATT的影响
| 层级 | 核心职责 | 主要PDU/帧格式 | 对GATT开发的影响 |
|---|---|---|---|
| GATT | 定义服务(Service)、特征(Characteristic)和配置文件的组织方式;封装应用数据模型。 | GATT 命令/响应(如发现服务、读写特征) | 开发者直接面向的编程接口;需处理 MTU 分段后的数据重组逻辑。 |
| ATT | 提供属性数据库的读写、通知、指示等原子操作;使用句柄(Handle)寻址属性。 | ATT PDU(操作码 + 句柄 + 值) | MTU 大小限制单次传输的有效载荷;通知/指示依赖 ATT 层流控。 |
| L2CAP | 多路复用上层协议(ATT、SM、SMP);执行分段与重组(SAR);管理 MTU 协商。 | L2CAP 帧(长度 + 通道标识 CID) | ATT 数据经 L2CAP 封装后加入 4 字节头部;CID 0x0004 用于 ATT 通道。 |
| HCI | 提供主机与控制器之间的命令/事件通信;承载 ACL 和 SCO 同步数据。 | HCI ACL 数据包(句柄 + PB标志 + BC标志 + 数据总长度) | HCI 传输层(UART/USB/SDIO)的延迟直接影响 GATT 写响应时间;流控由 HCI 层保证。 |
2.3 API入口与数据流边界
理解数据流边界是调试GATT问题的关键。一次典型的“写请求”从应用层到控制器的完整穿越如下图所示:
// 以 Zephyr / NimBLE 栈为例,GATT 写无响应(Write Without Response)的内部调用链
// 阶段 1:GATT 层封装应用数据
bt_gatt_write_without_response(conn_handle, value_handle, data, length);
// → 阶段 2:ATT 层构建 PDU
att_write_cmd(conn_handle, value_handle, data, length);
// → 阶段 3:L2CAP 层添加帧头并分段
l2cap_chan_send(chan, buf);
// → 阶段 4:HCI 层组装 ACL 数据包
hci_send_acl(buf);
// → 控制器通过射频发送
API 入口对照表(常见蓝牙协议栈)
Zephyr:
NimBLE:
TI BLE-Stack:
FreeRTOS Bluetooth:
Zephyr:
bt_gatt_notify(), bt_gatt_write(), bt_gatt_subscribe()NimBLE:
ble_gattc_write_flat(), ble_gattc_notify(), ble_gatts_send_notify()TI BLE-Stack:
GATT_WriteNoRsp(), GATT_Notification()FreeRTOS Bluetooth:
BtGattClient_sendWrite(), BtGattServer_sendNotification()
2.4 调试与常见错误
- GATT_ERROR_TIMEOUT (0x08): ATT 层超时。通常发生在对端 L2CAP 或 HCI 缓冲区满、ACL 链路拥塞时。应检查连接间隔和 HCI 流控状态。
- BLE_HS_ATT_ERR_INSUFFICIENT_RESOURCES (0x11): 资源不足。通常是 MTU 协商失败或 ATT 写请求超过对端缓冲区容量。建议将 MTU 协商到接近物理层限制(512~1024 字节)。
- EINVAL (errno 22): 在 Zephyr 中,频繁出现在调用
bt_gatt_service_register()时。通常是因为服务表中特征声明顺序违反 Core Specification(如缺少 Primary Service 声明,或 Characteristic 声明后未紧跟 Value 声明)。 - 连接突然断开(Connection Terminated Local): 经常由 ATT 层长时间未响应触发 L2CAP 链路监督超时(Supervision Timeout)导致。应确保 ATT 响应在 30 秒内返回。
ATT 超时陷阱: 上层应用在处理 GATT 写请求回调时,如果执行了耗时操作(如 Flash 写入、复杂计算)且未及时调用
att_write_rsp(),将触发 ATT 超时(30 秒)。这会导致 L2CAP 层直接断开链接,且不会重试。必须在回调中尽快回复,或将耗时任务推迟到工作队列执行。
2.5 性能与稳定性优化
- MTU 最大化: 默认 MTU 为 23 字节(仅 20 字节净荷)。通过 MTU Exchange 将 MTU 提升到 512+ 字节,单次 ATT 操作可传输 502+ 字节,降低约 95% 的协议层头部开销。
- 连接参数优化: 通知密集场景使用短连接间隔(例如 7.5 ms)和 0 延迟;省电场景使用长连接间隔(50 ms)及合理的从机延迟(Slave Latency)。参数不当会导致吞吐量下降或功耗异常。
- L2CAP SAR 与内存池: 大块数据在 L2CAP 层被分段为多个 HCI ACL 数据包。确保 HCI 驱动层的 ACL 接收缓冲池深度足够(建议 ≥ 6 个 MTU 大小的 buffer),否则会触发 HCI 层丢包和重传风暴。