1. 连接断开基础概念

做 BLE 开发的朋友,十有八九都被「连接断开」折磨过。设备连上没几秒就掉了,或者跑着跑着突然断连,日志里就留下一串错误码。说实话,我刚入行那会儿,看到断连日志就头大,完全不知道从哪查起。

这一章,我们就从最底层开始,把连接断开这件事彻底讲清楚。你理解了 BLE 的连接状态机,看懂了 HCI Disconnection Complete 事件,后面排查问题就会顺手很多。

BLE 连接状态机

BLE 的连接,说白了就是两个设备之间建立了一个「会话」。这个会话有生命周期,从建立到结束,中间会经历几个固定的状态。我习惯把这几个状态画成一张图,每次调试时对照着看,思路会清晰很多。

BLE 连接状态机 待机 (Standby) 广播 (Advertising) 扫描 (Scanning) 发起连接 (Initiating) 已连接 (Connected) 启动广播 启动扫描 停止广播 停止扫描 收到连接请求 发现目标 连接成功 断开连接 断开连接可以从「已连接」回到「待机」,也可以从其他状态直接进入「待机」

这张图里,我最想让你记住的是那个红色的「断开连接」箭头。它从「已连接」状态出发,直接回到「待机」。这意味着什么?意味着一旦断开,所有连接参数、缓冲区、服务句柄全部清零,设备得重新开始。

我的习惯:调试时,我会在状态切换点加日志。比如从「已连接」到「待机」的瞬间,打印出当前的 RSSI、连接间隔、以及最后一次交互的 GATT 操作。这些信息对定位断连原因非常有帮助。

断开连接的原因分类

断开连接,不是只有一种死法。我把它分成三大类:本地断开、远端断开、超时断开。每一类的根因和排查方向都不一样。

分类 触发方 典型原因 HCI 错误码
本地断开 本端主动调用 Disconnect API 应用层主动断开、GATT 操作异常、资源不足 0x16 (Connection Terminated by Local Host)
远端断开 对端设备主动断开 对端应用关闭连接、对端掉电、对端进入深度睡眠 0x13 (Connection Terminated by Remote User) 等
超时断开 链路层监控定时器 连接间隔内未收到包、干扰严重、距离过远 0x08 (Connection Timeout)

你看这个表格,三种断开方式的 HCI 错误码是不一样的。我个人觉得,最让人头疼的是超时断开,因为它往往不是单次事件,而是链路质量持续恶化的结果。

注意:不要一看到断连就怀疑是代码问题。我曾经遇到一个项目,设备在实验室跑得好好的,一到客户现场就频繁断连。查了两周,最后发现是现场有强干扰源。超时断开,很多时候是环境问题。

HCI Disconnection Complete 事件

当连接断开时,蓝牙控制器会向主机发送一个 HCI Disconnection Complete 事件。这个事件,就是断连的「尸检报告」。你读懂了它,就知道连接是怎么死的。

事件的结构是这样的:

HCI Disconnection Complete Event
├── Event Code: 0x05
├── Parameter Total Length: 4 bytes
├── Status: 0x00 (成功)
├── Connection Handle: 0x0001 (连接句柄)
├── Reason: 0x08 (断开原因)
└── (结束)

这里面最重要的字段就是 Reason。它用一个字节告诉你断开的具体原因。我整理了一份常用的 Reason 值对照表,你调试时可以直接查:

Reason 值 含义 常见场景
0x08 Connection Timeout 链路超时,最常见
0x13 Remote User Terminated Connection 对端主动断开
0x14 Remote Device Terminated Connection due to Low Resources 对端资源不足
0x15 Remote Device Terminated Connection due to Power Off 对端关机或掉电
0x16 Connection Terminated by Local Host 本端主动断开
0x22 LL Procedure Collision 链路层流程冲突
0x3E Connection Failed to be Established 连接建立失败

核心要点:拿到 HCI 日志后,第一件事就是看 Reason 字段。0x08 和 0x16 占了断连原因的 80% 以上。0x08 查链路质量,0x16 查应用层逻辑。

举个例子。有一次,我调试一个手环项目,手机 App 总是提示「设备已断开」。我抓了 HCI 日志,发现 Reason 是 0x14(Remote Device Terminated Connection due to Low Resources)。这说明手环端资源不够了。后来一查,是手环的 GATT 数据库太大,内存分配失败,导致连接被强制断开。

你看,如果没有 HCI 事件,我可能还在手机端瞎找原因。所以我的建议是:调试断连问题,先抓 HCI 日志,先看 Reason 字段。这是最高效的排查路径。

避坑指南:我曾经犯过一个错误——只看应用层的断连回调,不看 HCI 事件。结果应用层回调里只告诉你「断开了」,不告诉你原因。后来我养成了习惯,所有断连调试都从 HCI 日志开始。你也试试,效率会高很多。

嗯,这一章的内容就到这里。你理解了 BLE 连接状态机,知道了断连的三种分类,也学会了读 HCI Disconnection Complete 事件。后面几章,我们会深入每种断连原因的具体排查方法。