蓝牙笔记(1)
蓝牙技术栈笔记(1)
本笔记为作者再学习蓝牙Host协议栈的一些心得体会,如有不对的地方,请包含与谅解!
————by wsoz
蓝牙作为当今消费电子与短距离无线通信的主要手段,对于嵌入式工程师来说是很有必要进行学习的,我们有必要从浅到深去理解蓝牙的核心技术栈,包括BLE以及传统蓝牙。
蓝牙的简介
蓝牙,是一种支持设备短距离通信的无线电技术,能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换。
蓝牙版本 | 包含的技术 | 通俗理解 |
---|---|---|
< 4.0 | 只有 经典蓝牙 (BR/EDR) | 传统蓝牙 |
≥ 4.0 | 同时包含 经典蓝牙 (BR/EDR) 和 低功耗蓝牙 (BLE) | 一个包含两种技术的标准集合 |
- 蓝牙4.0之前的版本,只有传统蓝牙。
- 从蓝牙4.0开始,蓝牙标准就成了一个“大家庭”,里面既有“传统蓝牙”这位老成员,也加入了“BLE”这位新明星。 而之后的所有新功能和焦点,几乎都给了BLE。
单模蓝牙芯片:单一传统蓝牙芯片或者单一低功耗蓝牙芯片
双模蓝牙芯片:同时支持传统蓝牙跟低功耗蓝牙的芯片
BT Host:蓝牙主机部分,我一般把 HCI 架构的蓝牙协议栈叫做 Host
市面蓝牙分类
市面上的蓝牙可以归纳为三类:单芯片 SoC
方案、SoC + MCU
方案、Host + Controller
分离方案
特性 | 单芯片 SoC 方案 | SoC + MCU 方案 | Host + Controller 分离方案 |
---|---|---|---|
集成度 | 最高 | 中等 | 最低 |
硬件成本 | 最低 | 中等 | 最高 |
PCB面积 | 最小 | 中等 | 最大 |
功耗 | 最低 | 中等 | 最高 |
灵活性/性能 | 有限 | 高 | 极高 |
开发复杂度 | 较低(一体化) | 较高(双芯片协同) | 复杂(系统级开发) |
适用场景 | 成本敏感、尺寸/功耗要求高的IoT设备 | 功能复杂、需强大算力的嵌入式设备 | PC、手机、运行OS的复杂系统 |
单芯片 SoC
方案:
这是目前在物联网(IoT)领域最主流、最常见的方案。
-
核心架构:
- 一块芯片(System-on-Chip)集成了所有功能:
- 蓝牙射频和控制器 (Controller): 负责无线的物理收发。
- 蓝牙协议栈主机 (Host): 负责处理蓝牙协议逻辑。
- 微控制器 (MCU) 内核: 运行用户自己的应用程序 (Application)。
- 外设 (Peripherals): 如 GPIO, UART, SPI, I²C, ADC 等。
- 一块芯片(System-on-Chip)集成了所有功能:
-
典型应用:
- 智能手环、智能手表
- 蓝牙Beacon、防丢器
- 无线鼠标、键盘、遥控器
- 智能家居传感器(门锁、灯、温湿度计)
- 医疗健康监测设备(血糖仪、心率带)
SoC + MCU
方案:
当单个SoC的性能无法满足复杂应用的需求时,就会采用这种方案。
- 核心架构
- 使用两颗芯片。一颗是蓝牙SoC,但它只作为“蓝牙协处理器”或“网络处理器”(NCP),专门负责蓝牙通信。另一颗是功能更强大的主控MCU,负责运行复杂的应用程序。
- 两者之间通过 UART, SPI 等串行接口通信。
- 典型应用:
- 需要添加蓝牙功能的已有复杂产品。
- 带有复杂屏幕显示和本地运算的智能设备。
- 需要连接多种传感器并进行数据融合的物联网网关。
- 工业控制、自动化设备。
Host + Controller
分离方案:
-
核心架构:
- 严格遵循蓝牙规范中的 主机控制器接口 (HCI) 进行划分。
- Controller部分是一个独立的硬件模块(如USB蓝牙适配器、或主板上的一个芯片),它只负责蓝牙的底层物理层(PHY)和链路层(LL)。
- Host部分运行在一个强大的处理器上,通常是运行着完整操作系统(如Linux, Windows, Android)的CPU。操作系统内置了蓝牙协议栈的Host部分。
- 两者通过标准化的HCI接口(物理上可能是USB, UART, SDIO等)通信。
-
典型应用:
- 个人电脑 (PC)、笔记本电脑
- 智能手机、平板电脑
- 树莓派 (Raspberry Pi) 等开发板
- 车载信息娱乐系统
- 复杂的物联网网关(运行Linux系统)
HCI蓝牙架构简介
下图为几种核心架构:
这张图清晰地展示了蓝牙设备根据其支持的无线技术可以分为三种主要类型:
- 仅支持LE的设备(用于低功耗场景)
- 仅支持经典蓝牙的设备(用于高数据速率场景)
- 同时支持两者的双模设备(通用性最强,是现代智能设备的主流配置)
下面为具体的架构展开
下面来进行详细介绍各个层:
控制器层 (Controller / HW / BT Chip)
该层是蓝牙芯片内部的架构
公共部分:
- RF (Radio Frequency): 射频单元,是真正的模拟电路部分,负责在2.4GHz频段上发射和接收无线电信号。
- HCI(Host Controller Interface): 主机控制器接口层,芯片层面的 HCI 负责把协议栈的数据做处理,转换成芯片内部的动作。
经典蓝牙控制器 (BR/EDR)
- LMP (Link Manager Protocol): 链路管理协议,负责建立和管理两个设备间的蓝牙链路,包括认证、加密、功率控制等。
- BB (Baseband): 基带,负责处理数字信号,如跳频序列控制、数据包的编码解码、CRC校验等。
- Audio: 通常有专门的硬件处理音频数据的编解码(如SBC编码),减轻主机的负担。
低功耗蓝牙控制器 (LE)
- BLE LL (LE Link Layer): LE链路层,负责LE的状态管理(广播、扫描、连接)、数据包收发控制等。功能上对等于经典蓝牙的LMP和一部分BB。
- BLE PHY (LE Physical Layer): LE物理层,定义了无线调制解调方式和射频通道的使用。
传输层 (HCI Transport Layer)
这一层定义了主机(Host)和控制器(Controller)之间进行物理通信的方式,它负责承载所有HCI数据包(命令、事件、数据)的实际传输。常见的物理协议为:
- UART (通用异步收发器): 最常见和经典的传输方式,尤其在嵌入式设备中。它通过串行数据线(TX/RX)传输HCI数据包。由于UART本身只是一个简单的数据通道,蓝牙规范为此定义了专门的传输协议来确保不同类型的**HCI数据包(命令、事件、ACL、SCO)**能够被正确地打包、发送和接收。
- USB (通用串行总线): 在PC蓝牙适配器(Dongle)或笔记本电脑内置模块中非常普遍。
- SDIO (安全数字输入输出): 常见于智能手机、平板电脑等移动设备中。它利用SD卡接口标准来进行数据通信,提供了良好的性能和功耗表现。
- PCIe (外设组件快速互连): 在现代笔记本电脑中,为了实现更高的吞吐量,一些Wi-Fi和蓝牙的“二合一”或“三合一”网卡会通过PCIe接口与主系统连接。
协议代号 | 正式/通用名称 | 来源 | 总线类型 | 可靠性机制 | 主要特点/用途 |
---|---|---|---|---|---|
H2 | USB Transport Layer | 蓝牙SIG (官方标准) | USB | 依赖USB协议自身的可靠性 | 用于PC Dongle、笔记本内置模块等USB接口的设备。 |
H3 | BCSP (BlueCore Serial Protocol) | CSR/高通 (私有协议) | UART | 内置 (序列号, ACK/NAK, 滑动窗口) | 用于CSR/高通自家的芯片和软件栈,提供可靠传输。 |
H4 | UART Transport Layer | 蓝牙SIG (官方标准) | UART | 无 (依赖UART自身的正确性或硬件流控) | 最简单、最通用的UART传输方式,通过在数据包前加一个字节来标识包类型。 |
H5 | Three-Wire UART Transport Layer | 蓝牙SIG (官方标准) | UART | 内置 (序列号, ACK/NAK) | 官方标准的可靠UART传输协议,是H4的升级版,用于需要软件层面保证数据完整性的场景。需要流控 |
主机层 (Host)
该层运行在主处理器上(例如PC/手机的操作系统内核、或嵌入式设备的MCU),负责处理蓝牙协议栈中更高级的逻辑、数据管理和应用程序接口。它通过HCI(主机控制器接口)向控制器下发指令并接收事件,是实现蓝牙功能和服务的核心。同时也是我们学习的主要层面。
公共部分:
- HCI (Host Controller Interface) - 主机端:
- 主机端的HCI负责将上层协议(如L2CAP)的请求打包成标准的HCI命令 (Commands),通过传输层发送给控制器。
- 同时,它也负责接收并解析来自控制器的HCI事件 (Events)**和**数据 (Data),再递交给上层协议处理。它是主机软件与控制器硬件之间的“翻译官”。
- L2CAP (Logical Link Control and Adaptation Protocol): 逻辑链路控制与适配协议。
- 核心功能1: 协议/通道复用 (Multiplexing)。它允许多个上层协议(如RFCOMM、ATT)共享一条单一的物理链路(ACL链路)。它就像一个路由器,确保来自不同协议的数据包能被正确地发送和接收。
- 核心功能2: 分包与重组 (Segmentation and Reassembly)。它负责将上层传来的大数据包分割成适合控制器处理的小数据块,并在接收端将其重新组装成完整的数据包。
- 它同时服务于经典蓝牙和低功耗蓝牙,是数据传输的枢纽。
常见的各种协议:
-
RFCOMM(Serial Port Emulation):串口仿真协议,上层协议蓝牙电话,蓝牙透传 SPP 等协议都是直接走的 RFCOMM。
-
SDP(SERVICE DISCOVERY PROTOCOL):服务发现协议,服务发现协议(SDP)为应用程序提供了一种方法来发现哪些服务可用,并确定这些可用服务的特征。
-
OBEX(Object Exchange Protocol):对象交换协议,蓝牙电话本,蓝牙短信,文件传输等协议都是走的 OBEX协议。
-
HFP(Hands-Free Protocol):免提通话规范。用于蓝牙耳机、车载系统与手机之间进行通话控制和音频传输(通话音频,区别于A2DP的音乐音频)。
- AG (Audio Gateway) - 音频网关: 这通常是你的手机。它是所有通信的“网关”,负责处理实际的电话网络连接。
- HF (Hands-Free) - 免提设备: 这就是你的蓝牙耳机、车载蓝牙系统或智能音箱。它提供了用户接口(按钮)和音频输入/输出(麦克风和扬声器)。
-
HSP (Headset Profile):蓝牙耳机协议,最开始的蓝牙耳机协议。
-
SPP(SERIAL PORT PROFILE):在两个蓝牙设备之间模拟一条经典的RS-232物理串口线,实现蓝牙串口协议。
- DevA: 设备A。
- DevB: 设备B。
-
iAP (Accessory Protocol) : 苹果配件协议。苹果特有的蓝牙协议。
-
PBAP(Phone Book Access):蓝牙电话本访问协议,允许一个蓝牙设备(如车载系统)去“读取”另一个设备(你的手机)的电话簿和通话记录。
- PSE (Phone Book Server Equipment) - 电话簿服务器,这是你的手机。它存储着电话簿数据,并作为“服务器”向外提供这些数据。
- PCE (Phone Book Client Equipment) - 电话簿客户端,这是需要访问电话簿的设备,比如你的车载信息娱乐系统、智能手表,或是一些带有显示屏的高级耳机。它作为“客户端”去请求数据。
-
MAP(MESSAGE ACCESS PROFILE):蓝牙短信访问协议,允许一个蓝牙设备(如车载系统或智能手表)去访问、浏览、管理和发送另一个设备(你的手机)上的消息。
- MSE (Message Server Equipment)-消息服务器,智能手机,提供短信的服务器。
- MCE (Message Client Equipment)-消息客户端,车载系统 或 智能手表,需要拉取短信的客户端。
-
OPP(OBJECT PUSH PROFILE):对象推送协议,也就是发送给另一个设备。这是传统蓝牙功能中最基础、最广为人知的文件分享方式。
- Push Server (推送服务器)-接收并存储对象的一方。等待客户端的连接,在收到推送请求后,通常会提示用户“是否接收来自XX设备的文件?”,并在用户同意后接收文件。
- Push Client (推送客户端)-发起推送,发送对象的一方。由用户发起操作,连接到服务器,并将选定的文件/对象发送过去。
-
AVCTP(AUDIO/VIDEO CONTROL TRANSPORT PROTOCOL):音视频控制传输协议,是 AVRCP 的底层,直接走在L2CAP协议上的。
- Controller (CT) - 控制器:发起控制命令的设备。例如,你的蓝牙耳机、车载音响的控制面板、蓝牙遥控器。
- Target (TG) - 目标设备:接收并执行命令的设备。例如,正在播放音乐的智能手机、电脑或智能音箱。
-
AVDTP(AUDIO/VIDEO DISTRIBUTION TRANSPORT PROTOCOL):音视频分布传输协议,是 A2DP 的底层,AVDTP 的主要目的就是为高质量的音视频流(主要是音频)提供一个可靠的、实时的传输通道
-
HID(HUMAN INTERFACE DEVICE):人机接口协议,用于人机交互的低数据速率输入设备(如键盘、鼠标)提供一个标准化的无线连接方案。也是直接走在L2CAP协议上的。
-
A2DP(Advanced Audio Distribution): 蓝牙音乐协议,从一个设备(音源)单向传输到另一个设备(接收器)。
- Source (SRC) - 源设备,音频的来源,比如正在播放音乐的手机、电脑。
- Sink (SNK) - 接收器设备,音频的终点,负责接收并播放音频,比如蓝牙耳机、蓝牙音箱。
-
AVRCP(AUDIO/VIDEO REMOTE CONTROL PROFILE):蓝牙音乐控制协议,允许一个设备(控制器)远程控制另一个设备(目标设备)上的音视频播放功能。
- Controller (CT) - 控制器,发起遥控命令的设备。你的蓝牙耳机、车载音响的控制面板、智能手表、一个专门的蓝牙遥控器。
- Target (TG) - 目标设备,接收并执行遥控命令的设备,通常是媒体播放器本身。你的智能手机、笔记本电脑、智能电视。
-
ATT (Attribute Protocol) :蓝牙 BLE 属性协议,用于发现、读、写对端设备的协议(针对 BLE 设备),ATT允许设备作为服务端提供拥有关联值的属性集 ,让作为客户端的设备来发现、读、写这些属性;同时服务端能主动通知客户端。
- 属性:这是 ATT 的核心。每个属性都是一个标准格式的数据条目,由三部分组成。
- Handle (句柄):一个唯一的16位数字地址。这是属性的门牌号。客户端通过 Handle 来精确指定它想操作哪个属性。
- Type (类型):一个 UUID (通用唯一标识符)。这说明了这个属性里存放的是什么类型的数据,比如“这是心率测量值”或“这是电池电量”。
- Value (值):属性的实际数据。比如,数值
80
(代表心率80 BPM) 或95%
(代表电量)。
- 属性:这是 ATT 的核心。每个属性都是一个标准格式的数据条目,由三部分组成。
-
GATT (Generic Attribute Profile) - 通用属性规范,是一个框架规范,它建立在 ATT 协议之上,定义了如何使用 ATT 来发现、读取、写入和组织数据。所有 BLE 的应用层 Profile 都必须基于 GATT 来构建。
- Profile -> Service -> Characteristic的层次化结构
- Profile (规范):最高层,由一个或多个 Service 组成,旨在实现一个完整的应用场景。如心率规范 (Heart Rate Profile)。
- Service (服务):由一个或多个 Characteristic 组成,代表了设备的一个逻辑功能块。在一个心率设备上,可能会有 “Heart Rate Service”(心率服务)和 “Device Information Service”(设备信息服务)。
- Characteristic (特征):这是 GATT 结构中最基本的数据单元,代表一个具体的数据点。这也是客户端最终要读写的东西。
- Profile -> Service -> Characteristic的层次化结构
-
SM (Security Manager) : 蓝牙 BLE 安全管理协议。
开发板测试
我们拿到我们的开发板后对我们的部分功能根据文档进行测试,主要是SPP测试以及HFP测试。
SPP串口测试
SPP协议
是经典蓝牙,然后主要是构建简单的无线串口,比如常用的蓝牙模块HC-05/HC-06等。
先对我们的开发板进行BT_START
初始化,然后用我们的手机蓝牙调试助手连接上开发板的蓝牙,之后就可以直接进行数据的收发了。
我们手机端发送信息,在上位机端可以准确的接收到消息:
HFP测试
HFP协议
就是用于蓝牙耳机、车载系统与手机之间进行通话控制和音频传输。主要功能有:双向音频传输(Audio Transfer)
通话控制(Call Control) 状态同步(Status Synchronization)
我们上位机进行操作可以成功读取以及控制我们的手机进行拨号通话:
Transport传输层
本章主要介绍下常用的蓝牙 Transport 协议,USB 的 H2
,UART 的 H4/H5/BCSP
,SDIO
物理接口 | 逻辑协议 | 关键特点 / 常见应用 |
---|---|---|
USB | H2 | 高速,即插即用。PC蓝牙适配器、笔记本内置蓝牙。 |
UART | H4 | 最基础、最通用。各种开源协议栈、简单的嵌入式蓝牙模块。 |
H5 | 可靠性增强,带重传和流控。用于对稳定性要求高的嵌入式场景。 | |
BCSP | CSR/高通私有协议,可靠、高效。常见于使用CSR/高通芯片的设备。 | |
SDIO | (由SDIO规范定义) | 高速、低功耗。手机/平板内置蓝牙,特别是Wi-Fi/BT二合一芯片。 |
协议栈(Host)和蓝牙芯片(Controller)之间交换的,并不是“赤裸裸”的HCI数据,而是被**Transport Layer(传输层)**精心“打包”过的数据。
H4介绍及使用
HCI UART Transport Layer
是传输层最基础、最通用的的协议,我们进行学习也是以H4为主。
H4的帧结构是==1个字节的类型指定符+不定长数据==
+---------------------------+--------------------------------+
| Packet Indicator (1 byte) | Raw HCI Packet (可变长度) |
+---------------------------+--------------------------------+
类型指定符包含下面几种类型:
值 | 数据包类型 | 方向 | 描述 |
---|---|---|---|
0x01 | HCI Command Packet(命令) | Host → Controller | 主机向控制器发送的命令,如请求扫描、建立连接、复位芯片等。 |
0x02 | ACL Data Packet(应用数据) | Host ↔ Controller (双向) | 异步无连接数据。用于传输上层协议(如L2CAP, RFCOMM, SPP, A2DP)的用户数据,是绝大多数应用数据的载体。 |
0x03 | Synchronous Data Packet(语音数据) | Host ↔ Controller (双向) | 同步数据。主要用于传输语音数据(SCO/eSCO),如HFP免提通话中的音频流。 |
0x04 | HCI Event Packet(事件) | Controller → Host | 控制器向主机报告的事件。例如,对命令的响应(命令完成/状态事件)、发现了新设备、连接状态变化等。 |
0x05 | ISO Data Packet(新一代音频数据) | Host ↔ Controller (双向) | 同步数据流通道数据。这是蓝牙5.2及以后版本为LE Audio引入的新类型,用于传输高质量、低延迟的音频流。 |
然后我们的复位命令(HCI Rest Command)就是:0x01 0x03 0x0c 0x00
->包含了类型和Raw data
对于串口的配置:
配置项 | 设置值 | 备注 |
---|---|---|
波特率 (Baud rate) | 厂商自定义 (manufacturer-specific) | 虽然标准定义为厂商自定义,但业界有事实上的标准值,如 115200、921600、1M等。双方必须匹配。 |
数据位 (Data bits) | 8 | 固定为8位,用于传输一个完整的字节。 |
校验位 (Parity bit) | 无校验 (no parity) | 协议本身不进行奇偶校验。可靠性依赖于H5协议或稳定的物理连接。 |
停止位 (Stop bit) | 1 位 | 标准设置,用于标记一个字节传输的结束。 |
流控 (Flow control) | RTS/CTS | 硬件流控。这是保证高速通信时不丢包的关键,强烈推荐使用。 |
流控关闭响应时间 (Flow-off response time) | 厂商自定义 (manufacturer specific) | 指从发出“停止发送”信号(例如接收方拉高其RTS线)到发送方真正停止发送数据之间的延迟时间。 |
H4的UART需要使用流控:**H4协议本身是“盲目”的,它完全不知道接收方的处理能力和状态。**就是防止硬件层面的数据丢失。
纠错机制:
出错方向 | 谁先发现问题? | 第一步行动 | 恢复的标志 |
---|---|---|---|
主机 → 控制器 | 控制器 | 控制器发送“硬件故障事件”求救 | 控制器成功接收到主机的HCI_RESET 命令 |
控制器 → 主机 | 主机 | 主机直接发送HCI_RESET 命令 | 主机成功接收到控制器回复的指令完成事件 |
无论哪里出错,最终都是由主机(Host)通过发送 HCI_RESET
命令来收拾残局,并根据响应来确认通信是否恢复。
对于H4这个==UART通道的理解==:
对比项 | 蓝牙 + MCU 方案 | SoC 方案 |
---|---|---|
硬件形态 | 两块或更多独立芯片 | 一块 All-in-One 芯片 |
“电话线” | 物理的 (电路板上的导线) | 虚拟的 (芯片内部的逻辑接口) |
开发者视角 | 我需要配置MCU的UART外设,并用杜邦线/PCB正确接线。 | 我在操作系统层面和一个“设备文件”打交道,感觉像在用串口,但看不到物理线。 |
H4协议角色 | 完全一样:都是双方沟通时使用的“语言格式”。 | 完全一样:都是双方沟通时使用的“语言格式”。 |
简而言之就是这个UART通道无论是单soc还是配合MCU使用都是一样的,只是他们的形式不一样。
蓝牙工具介绍及使用
本文主要介绍调试蓝牙协议栈,定位蓝牙问题的工具。
工具类型 | 调试位置 | 调试什么? | 何时使用? |
---|---|---|---|
HCI 工具 | Host ↔ Controller | 协议交互、命令/事件流 | 调试驱动、协议栈,看Host和Controller的沟通是否顺畅。 |
芯片工具 | Controller 内部 | 固件、硬件状态、底层参数 | 烧录固件、射频校准、产线测试,或解决芯片相关的疑难杂症。 |
空中抓包 | 设备 ↔ 设备 (空中) | 无线数据包、时序、加密 | 调试连接/配对失败、设备兼容性、丢包、干扰等问题,获取最终证据。 |
HCI录制工具
HCI工具通过工作原理分为了两类:
-
软件方式: 在操作系统层面(如Linux, Android, Windows)截获所有进出蓝牙驱动的数据包。常用的有btsnoop/hcidump 。
一般协议栈会有一个把蓝牙芯片跟蓝牙协议栈交互的封包保存文件的功能,然后再用特定的软件(Wireshark/Ellisys/Frontline)打开,当然前提是你保存的是他们认识的格式。
-
硬件方式: 使用逻辑分析仪等工具,物理地“窃听”UART或USB总线上的数据。
硬件方式就是直接通过外部监测,然后通过上位机(Ellisys/Frontline)实时显示蓝牙协议栈跟蓝牙芯片的交互封包。
HCI录制工具的作用:
- 主机是否发送了正确的
HCI 命令
?(例如,HCI_Reset
命令是否是0x01 0x03 0x0c 0x00
)。 - 控制器是否返回了预期的
HCI 事件
?(例如,连接成功后,是否收到了Connection Complete Event
)。 - 上层的应用数据(
ACL Data
)是否被正确地打包并传递给了控制器? - H4/H5协议的封装和解析是否正确?
芯片内部工具
这种通常是抓取芯片内部log或者执行流程的软件,需要原厂提供方法以及工具。通过芯片专用的调试接口(如JTAG, SWD)或厂商定义的私有命令(Vendor Specific Command),直接访问芯片的内存、寄存器和固件功能。
芯片内部工具的作用:
- 给芯片烧录/升级固件。
- 读取芯片的内部日志(比HCI Event更底层、更详细)。
- 强制芯片进入各种测试模式,如DTM (Direct Test Mode),用于射频性能测试。
- 修改芯片的底层配置,如**发射功率、晶振校准值、蓝牙地址(BD_ADDR)**等。
- 查看芯片内部状态,如内存使用情况、任务调度、中断统计等。
空中抓包工具
这个需要特殊的sniffer硬件工具+上位机,抓取的是本地芯片跟对端芯片之间的交互数据,没有HCI层的数据,作用于设备之间的 空中无线信道 (2.4GHz)。
传统蓝牙我们用的比较多的是:Ellisys/Frontline
BLE有便宜的方案:基本上NRF,TI CC系列都有抓包
空中抓包工具的作用:
- “绝对的真相”:无论Host或Controller认为自己发了什么,Sniffer抓到的才是真正发射到空中的东西。
- 连接建立过程中的底层握手包(
Advertising PDU
,Connection Request
)。 - 加密协商和配对过程中的数据包交互。
- 数据传输的时序问题,如包间隔(IFS)。
- 丢包和重传情况。
- 由Wi-Fi或其他2.4GHz设备干扰导致的问题。
Btsnoop
对于我们个人学习而言掌握Btsnoop 已经够用了,所有我们着重学习一下Bstnoop。
Btsnoop 本身不是一个工具,而是一个文件格式标准。
Btsnoop 用于记录蓝牙协议栈跟芯片交互的数据,一般用于在分析蓝牙问题的时候有很大的用途,能够快速定位问题所在,一般协议栈都有整合这个或者类似功能。
- 优点:
- 零成本: 无需任何额外硬件。
- 超便捷: 在安卓和Linux上获取非常容易。
- 功能强大: 完美适用于调试上层协议栈、应用逻辑、命令/事件交互流程。
- 局限:
- 无法看到物理层问题: 如果是UART传输过程中数据位出错(硬件问题),Btsnoop 是看不到的,因为它是在驱动层面捕获的,数据可能已经错了。
- 无法看到空中问题: 它不知道空中发生了什么,无法用于调试设备兼容性、空中丢包、信号干扰等问题。
查看Btsnoop
手机启动btsnoop工具需要打开开发者选项然后开启HCI信息收集去对应的文件目录下查询
嵌入式上位机查看btsnoop则可以通过上位机如:wireshark、Frontline、Ellisys
Btsnoop格式
一个 Btsnoop 文件由一个 全局文件头 (File Header) 和 一个或多个数据包记录 (Packet Records) 顺序排列组成同时这些排列均是大端字节序**(高位在前)**。
-
File Header
(16字节)-
identification_pattern
(8字节)任何程序打开一个文件,首先读取这8个字节,如果匹配,就知道这是一个 Btsnoop 文件,然后就可以按规定格式继续解析
固定的 ASCII 字符串
"btsnoop"
,以一个空字符\0
结尾 (0x62 0x74 0x73 0x6e 0x6f 0x6f 0x70 0x00
) -
Version_number
(4字节)暂时一直为1(
0x00 0x00 0x00 0x01
) -
datalink_type
(4字节)作用是告诉上位机数据包是什么类型的应该调用对应的解析器来解析
1001 (HCI UART - H4)
: 最常见的一种。表示 HCI 数据包是通过 UART 传输的,并带有 H4 协议的包类型指示符(1字节前缀)。1002 (HCI BCSP)
: BlueCore Serial Protocol,CSR/高通芯片使用的一种专有同步协议。1003 (HCI SDLC)
: 另一种同步协议。1004 (HCI USB)
: 表示 HCI 数据包是通过 USB 传输的。USB HCI 包有其特殊的格式,这个值会告知 Wireshark 按 USB Bluetooth Adapter 的规范来解析。
注意:datalink_type 在 Android 中不管是 H5 还是 BCSP都会剥开 transport 数据,来以 H4 方式存储。
-
-
Packet recored
(24字节+不定长数据包)-
original_length
(4字节)数据包在被捕获时的原始长度。
-
included_length
(4字节)这个记录中实际存储的数据包长度。通常与
original_length
相等。 -
packet_record_flags
(4字节)Bit 位 官方定义 说明 0 Direction flag (方向标志)
0 = Sent (发送)
1 = Received (接收)这是最重要的位,决定了数据包的流向是 Host -> Controller 还是 Controller -> Host。 1 Command flag (命令标志)
0 = Data (数据)
1 = Command/Event (命令/事件)用于区分这是控制类报文 (Command, Event) 还是数据类报文 (ACL, SCO)。 2-31 Reserved (保留) 始终为0。 下面为更加具体的包标识定义
HCI 包类型 方向 (逻辑) Bit 1 (类型) Bit 0 (方向) flags
最终值 (Hex)HCI Command 协议栈 -> 芯片 (Sent) 1 (Command) 0 (Sent) 0x02
HCI Event 芯片 -> 协议栈 (Received) 1 (Event) 1 (Received) 0x03
HCI ACL Out 协议栈 -> 芯片 (Sent) 0 (Data) 0 (Sent) 0x00
HCI ACL In 芯片 -> 协议栈 (Received) 0 (Data) 1 (Received) 0x01
HCI SCO Out 协议栈 -> 芯片 (Sent) 0 (Data) 0 (Sent) 0x00
HCI SCO In 芯片 -> 协议栈 (Received) 0 (Data) 1 (Received) 0x01
HCI ISO Out 协议栈 -> 芯片 (Sent) 0 (Data) 0 (Sent) 0x00
HCI ISO In 芯片 -> 协议栈 (Received) 0 (Data) 1 (Received) 0x01
-
cumulative_drops
(4字节)从开始捕获到当前记录之间,被系统丢弃的数据包数量,若某些无法实现丢包计数通常设置为0。
-
timestamp_microseconds
(8 字节)时间戳的秒部分。表示从 Epoch (1970-01-01 00:00:00 UTC) 到捕获数据包时所经过的秒数。
-
packet_data
(可变长度)我们的HCI数据部分,长度不定。
-
疑惑解释:
-
Btsnoop工具是站在谁的角度进行分析的?
永远站在“主机 (Host)”的角度,这个“主机”就是运行操作系统(如 Android, Linux, Windows)和蓝牙协议栈的那台设备,通常就是你的手机、电脑或者开发板。同时需要注意:
- Host 不是唯一的: 一个蓝牙连接中有两个蓝牙系统(两个Host和Controller)
- Btsnoop 日志是本地的: 它只记录抓取日志的那个设备其内部的 Host 与 Controller 之间的通信。
-
Flags的终值出现相同标志0x01或者0x00会不会无法区分?
不会混淆。因为
flags
字段不是唯一的信息源!在我们学过的Transport层的H4的帧结构种会有一个类型指定符区分。
Btsnoop数据存储
为了进行分析我们肯定需要将我们Btsnoop数据存储起来,让我们的 MCU 的固件代码中手动实现一个“Btsnoop记录器,之后通过PC端对工具我们的数据进行分析。
目前大致的存储方向有两个:一个是直接通过接口(UART、USB)接我们的PC机进行转存,另一个是直接通过MCU外挂存储器(Flash、SD卡)直接存储后续我们直接通过其他方式读出来进行分析。
方案 | 核心场景 | 实现方式 | 优点 | 缺点 |
---|---|---|---|---|
1. 通过 UART 发送 | 实验室桌面调试 | 将 Btsnoop 二进制流(文件头+每个包的记录)通过 UART 实时发送至 PC,PC 端使用串口工具接收并保存为文件。 | - 实现简单,MCU 资源占用少 - 通用性强,几乎所有MCU都支持 | - 存在速度瓶颈,高速通信时可能丢日志 - 必须连接 PC,无法独立工作 |
2. 通过 Segger RTT 发送 | 高性能桌面调试 | 通过 J-Link 调试器的 RTT 功能建立高速数据通道,将日志流发送至 PC,使用 RTT Logger 工具保存。 | - 速度极快,几乎不丢数据 - 非侵入式,不影响 MCU 性能和时序 | - 强依赖 Segger J-Link 硬件 |
3. 存储到外部 Flash / SD 卡 | 现场测试 长时间监控 离线调试 | 在固件中集成文件系统 (如 FatFs, LittleFS),将 Btsnoop 日志作为文件写入到外挂的 Flash 芯片或 SD 卡中。 | - 可独立工作,无需 PC - 存储容量大,可长时间记录 - 日志文件易于获取和管理 | - 实现复杂,占用代码和RAM资源多 - 有写入延迟,可能需 RAM 缓冲 - 消耗 Flash 擦写寿命 |
4. 存储到 RAM 环形缓冲区 | 捕获系统崩溃/错误前的瞬间日志(事后追溯) | 在 RAM 中开辟环形缓冲区,循环存入最新的日志数据,当异常发生时,通过调试器或串口 dump 出缓冲区内容。 | - 读写速度极快,完全无阻塞 - 实现相对简单 | - 容量极小,只能记录短期数据 - 掉电数据丢失 |
Btsnoop工具使用
我们会介绍三种分别是Wireshark、Frontline 、Ellisys 进行查看我们的Btsnoop数据。
首先需要知道的是Btsnoop的格式是方便工具进行解析的
然后我们的原始数据就是我们传输层传输的数据(类型指定符号+HCI data)
大致的分析思路就是:
- 先看宏观:有没有“语法错误”包?
- 再看对话:请求和响应能配上对吗?响应是“成功”还是“失败”?
- 然后看剧情:整个操作的顺序和时序符合逻辑吗?
- 最后看内容:如果协议都走通了,那传输的数据内容本身对不对?
Wireshark
对于这个软件,我们直接将我们的log文件拖入软件就可以进行查看
为了区分这个包的类型,我们可以在试图中打开着色规则进行作色
软件主要分成了几个试图板块:
- 试图栏包含我们的整个记录的所有数据包(上方可以过滤搜索 eg:bthci_cmd)
- 选中包的数据汇总栏
- 原始数据栏
Ellisys
该软件我们就需要通过File->Import来导入我们的log数据进行查看
左边的框就是协议交互每包数据的显示,右边的框就是特定选中数据包协议的解析,也可以查看原始数据。