蓝牙协议栈
从软件开发者角度理解蓝牙协议栈,掌握各层职责、数据包结构和 API 调用。
📐 协议栈分层架构
flowchart TD
subgraph Host["主机 Host (软件层)"]
App["应用层 Application
业务逻辑 + Profiles"] GATT["GATT 层
服务/特征值管理"] GAP["GAP 层
广播/扫描/连接"] ATT["ATT 层
属性协议"] SMP["SMP 层
安全配对"] L2CAP["L2CAP 层
信道复用"] end subgraph HCI["HCI 接口"] HCI_CMD["HCI Command"] HCI_EVT["HCI Event"] HCI_ACL["HCI ACL Data"] end subgraph Controller["控制器 Controller (固件层)"] LL["Link Layer
状态机 + 调度"] PHY["PHY 层
射频收发"] end App --> GATT GATT --> ATT GAP --> ATT ATT --> L2CAP SMP --> L2CAP L2CAP --> HCI_ACL HCI_CMD --> HCI_EVT HCI_ACL --> LL HCI_CMD --> LL LL --> PHY style Host fill:#e3f2fd,stroke:#007bff style HCI fill:#fff3cd,stroke:#ffc107 style Controller fill:#d4edda,stroke:#28a745 style App fill:#007bff,color:#fff style L2CAP fill:#17a2b8,color:#fff
业务逻辑 + Profiles"] GATT["GATT 层
服务/特征值管理"] GAP["GAP 层
广播/扫描/连接"] ATT["ATT 层
属性协议"] SMP["SMP 层
安全配对"] L2CAP["L2CAP 层
信道复用"] end subgraph HCI["HCI 接口"] HCI_CMD["HCI Command"] HCI_EVT["HCI Event"] HCI_ACL["HCI ACL Data"] end subgraph Controller["控制器 Controller (固件层)"] LL["Link Layer
状态机 + 调度"] PHY["PHY 层
射频收发"] end App --> GATT GATT --> ATT GAP --> ATT ATT --> L2CAP SMP --> L2CAP L2CAP --> HCI_ACL HCI_CMD --> HCI_EVT HCI_ACL --> LL HCI_CMD --> LL LL --> PHY style Host fill:#e3f2fd,stroke:#007bff style HCI fill:#fff3cd,stroke:#ffc107 style Controller fill:#d4edda,stroke:#28a745 style App fill:#007bff,color:#fff style L2CAP fill:#17a2b8,color:#fff
📋 各层职责与开发接口
图表总览
flowchart TB
subgraph Host["主机 Host (开发者关注)"]
App["Application
📱 业务逻辑
API: read/write"] GATT["GATT
🔌 服务/特征值
API: addService"] GAP["GAP
📡 广播/连接
API: startAdvertising"] ATT["ATT
📨 属性协议
内部使用"] L2CAP["L2CAP
🔀 信道复用
API: connectChannel"] end subgraph HCI["HCI 接口"] HCI_CMD["HCI Command⬇️"] HCI_EVT["HCI Event⬆️"] HCI_ACL["HCI ACL Data↔️"] end subgraph Controller["控制器 (固件自动处理)"] LL["Link Layer
状态机 + 调度"] PHY["PHY
射频收发"] end App --> GATT GATT --> ATT GAP --> ATT ATT --> L2CAP L2CAP --> HCI_ACL HCI_ACL --> LL HCI_CMD --> LL LL --> HCI_EVT LL --> PHY style Host fill:#e3f2fd,stroke:#007bff style HCI fill:#fff3cd,stroke:#ffc107 style Controller fill:#d4edda,stroke:#28a745 style App fill:#007bff,color:#fff style GATT fill:#17a2b8,color:#fff style GAP fill:#28a745,color:#fff
📱 业务逻辑
API: read/write"] GATT["GATT
🔌 服务/特征值
API: addService"] GAP["GAP
📡 广播/连接
API: startAdvertising"] ATT["ATT
📨 属性协议
内部使用"] L2CAP["L2CAP
🔀 信道复用
API: connectChannel"] end subgraph HCI["HCI 接口"] HCI_CMD["HCI Command⬇️"] HCI_EVT["HCI Event⬆️"] HCI_ACL["HCI ACL Data↔️"] end subgraph Controller["控制器 (固件自动处理)"] LL["Link Layer
状态机 + 调度"] PHY["PHY
射频收发"] end App --> GATT GATT --> ATT GAP --> ATT ATT --> L2CAP L2CAP --> HCI_ACL HCI_ACL --> LL HCI_CMD --> LL LL --> HCI_EVT LL --> PHY style Host fill:#e3f2fd,stroke:#007bff style HCI fill:#fff3cd,stroke:#ffc107 style Controller fill:#d4edda,stroke:#28a745 style App fill:#007bff,color:#fff style GATT fill:#17a2b8,color:#fff style GAP fill:#28a745,color:#fff
各层详细说明
flowchart LR
subgraph L7["应用层"]
A7["职责: 业务逻辑
接口: Profile SDK
API: readCharacteristic
write()"] end subgraph L6["GATT 层"] A6["职责: 服务管理
接口: GATT Profile
API: addService
addCharacteristic"] end subgraph L5["GAP 层"] A5["职责: 设备发现
接口: Advertising API
API: startAdvertising
connect"] end subgraph L4["ATT 层"] A4["职责: 属性访问
接口: 内部使用
API: Read/Write
Notify Request"] end subgraph L3["L2CAP 层"] A3["职责: 信道复用
接口: LE Credit Based
API: connectChannel
send"] end subgraph L2["HCI 层"] A2["职责: Host-Controller
接口: HCI Command/Event
API: hci_send_cmd"] end subgraph L1["LL+PHY"] A1["职责: 射频/调度
接口: 固件实现
API: 自动处理"] end L7 --> L6 L6 --> L5 L5 --> L4 L4 --> L3 L3 --> L2 L2 --> L1 style L7 fill:#007bff,color:#fff style L6 fill:#17a2b8,color:#fff style L5 fill:#28a745,color:#fff style L4 fill:#ffc107,color:#000 style L3 fill:#fd7e14,color:#fff style L2 fill:#6f42c1,color:#fff style L1 fill:#6c757d,color:#fff
接口: Profile SDK
API: readCharacteristic
write()"] end subgraph L6["GATT 层"] A6["职责: 服务管理
接口: GATT Profile
API: addService
addCharacteristic"] end subgraph L5["GAP 层"] A5["职责: 设备发现
接口: Advertising API
API: startAdvertising
connect"] end subgraph L4["ATT 层"] A4["职责: 属性访问
接口: 内部使用
API: Read/Write
Notify Request"] end subgraph L3["L2CAP 层"] A3["职责: 信道复用
接口: LE Credit Based
API: connectChannel
send"] end subgraph L2["HCI 层"] A2["职责: Host-Controller
接口: HCI Command/Event
API: hci_send_cmd"] end subgraph L1["LL+PHY"] A1["职责: 射频/调度
接口: 固件实现
API: 自动处理"] end L7 --> L6 L6 --> L5 L5 --> L4 L4 --> L3 L3 --> L2 L2 --> L1 style L7 fill:#007bff,color:#fff style L6 fill:#17a2b8,color:#fff style L5 fill:#28a745,color:#fff style L4 fill:#ffc107,color:#000 style L3 fill:#fd7e14,color:#fff style L2 fill:#6f42c1,color:#fff style L1 fill:#6c757d,color:#fff
开发者关注点
| 层 | 职责 | 开发者接口 | 典型 API | 关注程度 |
|---|---|---|---|---|
| Application | 业务逻辑实现 | Profile SDK | readCharacteristic(), write() | ⭐⭐⭐⭐⭐ |
| GATT | 服务/特征值管理 | GATT Profile | addService(), addCharacteristic() | ⭐⭐⭐⭐⭐ |
| GAP | 设备发现与连接 | Advertising/Scan API | startAdvertising(), connect() | ⭐⭐⭐⭐⭐ |
| ATT | 属性访问协议 | 内部使用 | Read/Write/Notify Request | ⭐⭐⭐ |
| L2CAP | 信道复用与分段 | LE Credit Based | connectChannel(), send() | ⭐⭐ |
| HCI | 主机控制器通信 | HCI Command/Event | hci_send_cmd(), hci_read_evt() | ⭐⭐⭐ |
| Link Layer | 连接调度与状态机 | 固件实现 | 自动处理 | ⭐ |
| PHY | 射频收发 | 固件实现 | 自动处理 | ⭐ |
🔧 Host 层详解(开发者关注)
GAP 层 - 设备发现与连接
sequenceDiagram
participant App as 应用层
participant GAP as GAP 层
participant LL as Link Layer
App->>GAP: 配置广播参数
GAP->>LL: HCI_LE_Set_Advertising_Parameters
App->>GAP: 设置广播数据
GAP->>LL: HCI_LE_Set_Advertising_Data
App->>GAP: 启动广播
GAP->>LL: HCI_LE_Set_Advertise_Enable
LL-->>GAP: 广播完成事件
GAP-->>App: 回调通知
// GAP 广播配置示例 (Nordic SDK)
ble_gap_adv_params_t adv_params = {
.properties = {
.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED
},
.p_peer_addr = NULL,
.interval = {
.min = BLE_GAP_ADV_INTERVAL_MIN, // 160 * 0.625ms = 100ms
.max = BLE_GAP_ADV_INTERVAL_MAX
},
.timeout = 0,
.filter_policy = BLE_GAP_ADV_FP_ANY
};
// 设置广播数据
uint8_t adv_data[] = {
0x02, 0x01, 0x06, // Flags
0x03, 0x03, 0xAA, 0xFE, // Service UUID (0xFEAA)
0x0B, 0x09, 'M', 'y', 'D', 'e', 'v', 'i', 'c', 'e' // Device Name
};
sd_ble_gap_adv_start(&adv_params, 1);
GATT 层 - 服务与特征值
flowchart TB
subgraph Server["GATT Server (外设)"]
S1[服务 180F 电池]
C1[特征值 2A19 电量]
D1[描述符 2902 CCCD]
end
subgraph Client["GATT Client (中心)"]
C2[发现服务]
C3[发现特征值]
C4[读写操作]
end
S1 --> C1
C1 --> D1
C2 --> C3
C3 --> C4
Client <-->|"ATT 请求/响应"| Server
style Server fill:#d4edda,stroke:#28a745
style Client fill:#e3f2fd,stroke:#007bff
// GATT 服务定义示例
// 电池服务 UUID: 0x180F
// 电池电量特征值 UUID: 0x2A19
ble_gatts_char_md_t char_md = {
.char_props.read = 1,
.char_props.notify = 1,
.p_char_user_desc = NULL,
.p_char_pf = NULL,
.p_user_desc_md = NULL,
};
ble_uuid_t uuid = {
.uuid = BLE_UUID_BATTERY_LEVEL_CHAR,
.type = BLE_UUID_TYPE_BLE
};
ble_attr_char_value_t char_val = {
.def_val = 100, // 初始电量 100%
.max_len = 1,
};
// 添加特征值到服务
sd_ble_gatts_characteristic_add(service_handle, &char_md, &attr, &char_handle);
L2CAP 层 - 信道复用
| 信道 ID (CID) | 用途 | 说明 |
|---|---|---|
| 0x0000 | NULL | 保留 |
| 0x0001 | ATT | 属性协议 (GATT 使用) |
| 0x0002 | SMP | 安全管理器 |
| 0x0003 | LE SMP | 低功耗安全配对 |
| 0x0004-0x003F | 固定信道 | 保留 |
| 0x0040-0xFFFF | 动态信道 | LE Credit Based 连接 |
📦 数据包结构详解
完整数据流向
flowchart LR
App["应用数据"] --> GATT["GATT PDU"]
GATT --> ATT["ATT PDU"]
ATT --> L2CAP["L2CAP Header + Payload"]
L2CAP --> HCI["HCI ACL Packet"]
HCI --> LL["LL Data PDU"]
LL --> PHY["RF Packet"]
subgraph Host["Host 添加头部"]
GATT
ATT
L2CAP
end
subgraph Controller["Controller 添加头部"]
HCI
LL
PHY
end
style App fill:#f8f9fa
style Host fill:#e3f2fd,stroke:#007bff
style Controller fill:#d4edda,stroke:#28a745
style PHY fill:#f8f9fa
HCI ACL 数据包格式
// HCI ACL Data Packet
// 用于 Host ↔ Controller 传输 GATT 数据
+----------------+----------------+----------------+
| HCI Header | ACL Header | L2CAP PDU |
| (4 bytes) | (4 bytes) | (可变) |
+----------------+----------------+----------------+
// HCI Header 结构
typedef struct {
uint16_t handle; // 连接句柄 (12 位) + 标志 (4 位)
uint16_t dlen; // 数据长度
} hci_acl_header_t;
// ACL Header 结构
typedef struct {
uint16_t dlen; // L2CAP 数据长度
uint16_t cid; // 信道 ID (ATT=0x0001, SMP=0x0002)
} l2cap_header_t;
// 示例:发送 GATT 通知
uint8_t packet[] = {
// HCI ACL Header
0x00, 0x40, // Handle=0, PB=00, BC=00
0x17, 0x00, // Data Length=23
// L2CAP Header
0x13, 0x00, // L2CAP Length=19
0x01, 0x00, // CID=0x0001 (ATT)
// ATT Handle Value Notification
0x1B, // Opcode: Handle Value Notification
0x04, 0x00, // Handle=0x0004
0x64, // Value: 100%
};
ATT PDU 格式
// ATT PDU 通用格式
+--------+------------------+
| Opcode | Parameters |
| 1 byte | 可变长度 |
+--------+------------------+
// 常用 ATT Opcode
#define ATT_OP_ERROR 0x01
#define ATT_OP_EXCHANGE_MTU_REQ 0x02
#define ATT_OP_EXCHANGE_MTU_RSP 0x03
#define ATT_OP_FIND_INFO_REQ 0x04
#define ATT_OP_FIND_INFO_RSP 0x05
#define ATT_OP_FIND_BY_TYPE_REQ 0x06
#define ATT_OP_FIND_BY_TYPE_RSP 0x07
#define ATT_OP_READ_BY_TYPE_REQ 0x08
#define ATT_OP_READ_BY_TYPE_RSP 0x09
#define ATT_OP_READ_REQ 0x0A
#define ATT_OP_READ_RSP 0x0B
#define ATT_OP_READ_BLOB_REQ 0x0C
#define ATT_OP_READ_BLOB_RSP 0x0D
#define ATT_OP_READ_MULTI_REQ 0x0E
#define ATT_OP_READ_MULTI_RSP 0x0F
#define ATT_OP_READ_BY_GROUP_REQ 0x10
#define ATT_OP_READ_BY_GROUP_RSP 0x11
#define ATT_OP_WRITE_REQ 0x12
#define ATT_OP_WRITE_RSP 0x13
#define ATT_OP_WRITE_CMD 0x52
#define ATT_OP_PREP_WRITE_REQ 0x16
#define ATT_OP_PREP_WRITE_RSP 0x17
#define ATT_OP_EXEC_WRITE_REQ 0x18
#define ATT_OP_EXEC_WRITE_RSP 0x19
#define ATT_OP_HANDLE_VALUE_NOTIF 0x1B
#define ATT_OP_HANDLE_VALUE_IND 0x1D
#define ATT_OP_HANDLE_VALUE_CFM 0x1E
各层 MTU 对比
| 层 | PDU 名称 | 最大负载 | 头部开销 |
|---|---|---|---|
| PHY | Physical Channel PDU | 37 bytes | 10 bytes |
| LL | LL Data PDU | 27 bytes (BLE 4.x) | 2 bytes |
| LL | LL Data PDU | 251 bytes (BLE 5.0+) | 2 bytes |
| L2CAP | L2CAP PDU | 65535 bytes | 4 bytes |
| ATT | ATT PDU | MTU - 3 bytes | 1 byte (Opcode) |
| GATT | Attribute Value | MTU - 4 bytes | 2 bytes (Handle) + 1 byte |
🔌 HCI 命令速查
常用 LE Controller 命令 (OGF=0x08)
| OCF | 命令名称 | 功能 | 返回事件 |
|---|---|---|---|
| 0x0001 | LE_Set_Event_Mask | 配置 LE 事件掩码 | Command_Complete |
| 0x0002 | LE_Read_Buffer_Size | 读取 Controller 缓冲区大小 | Command_Complete |
| 0x0003 | LE_Read_Local_Supported_Features | 读取本地支持的特性 | Command_Complete |
| 0x0008 | LE_Set_Random_Address | 设置随机地址 | Command_Complete |
| 0x000A | LE_Set_Advertising_Parameters | 配置广播参数 | Command_Complete |
| 0x000B | LE_Set_Advertising_Data | 设置广播数据 | Command_Complete |
| 0x000C | LE_Set_Scan_Response_Data | 设置扫描响应数据 | Command_Complete |
| 0x000D | LE_Set_Advertise_Enable | 启用/禁用广播 | Command_Complete |
| 0x000E | LE_Set_Scan_Parameters | 配置扫描参数 | Command_Complete |
| 0x000F | LE_Set_Scan_Enable | 启用/禁用扫描 | Command_Complete |
| 0x0011 | LE_Create_Connection | 发起连接 | LE_Connection_Complete |
| 0x0016 | LE_Read_White_List_Size | 读取白名单大小 | Command_Complete |
| 0x0020 | LE_Read_PHY | 读取当前 PHY | Command_Complete |
| 0x0031 | LE_Set_Default_PHY | 设置默认 PHY | Command_Complete |
| 0x0034 | LE_Set_Extended_Advertising_Parameters | 扩展广播参数 (BLE 5.0+) | Command_Complete |
HCI 命令格式示例
// HCI 命令包格式
// +----------------+----------------+----------------+
// | Opcode (2B) | Parameter Len | Parameters |
// | OGF(10b)+OCF(6b)| (1B) | (可变) |
// +----------------+----------------+----------------+
// 示例:LE_Set_Advertising_Parameters
// OGF = 0x08, OCF = 0x000A
// Opcode = 0x200A
uint8_t hci_cmd[] = {
0x0A, 0x20, // Opcode: OGF=0x08, OCF=0x000A
0x1F, // Parameter Length: 31 bytes
// Advertising Parameters
0xA0, 0x00, // Interval Min: 160 * 0.625ms = 100ms
0xA0, 0x00, // Interval Max
0x00, // Type: ADV_IND
0x00, 0x00, // Own Address Type
0x00, // Peer Address Type
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Peer Address
0x07, // Channel Map: 37,38,39
0x00, // Filter Policy
};
💻 跨平台 HCI 调用示例
Linux BlueZ HCI 调用
#include
#include
#include
int main() {
int dev_id = hci_get_route(NULL);
int dev_fd = hci_open_dev(dev_id);
// LE_Set_Advertising_Parameters
struct hci_request hci_req = {
.ogf = OGF_LE_CTL,
.ocf = OCF_LE_SET_ADV_PARAMETERS,
.cparam = &adv_params,
.clen = LE_SET_ADV_PARAMETERS_CP_SIZE,
.rparam = &rp,
.rlen = LE_SET_ADV_PARAMETERS_RP_SIZE,
};
hci_send_req(dev_fd, &hci_req, 1000);
// LE_Set_Advertise_Enable
uint8_t enable = 0x01;
hci_send_cmd(dev_fd, OGF_LE_CTL, OCF_LE_SET_ADV_ENABLE, 1, &enable);
return 0;
}
Python pybluez 调用
import bluetooth._bluetooth as bluez
# 打开 HCI 设备
dev_id = 0
sock = bluez.hci_open_dev(dev_id)
# 发送 HCI 命令
# LE_Set_Advertising_Parameters
cmd = bytes([
0x0A, 0x20, # Opcode
0x1F, # Length
# ... 参数
])
sock.send(cmd)
# 读取事件
evt = sock.recv(255)
print(f"Event: {evt.hex()}")
Nordic SDK (SoftDevice)
#include "nrf_sdm.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
// 启用 SoftDevice
void softdevice_init(void) {
nrf_clock_lf_cfg_t clock_cfg = NRF_CLOCK_LFCLK_RC;
// 初始化 SoftDevice
sd_softdevice_enable(&clock_cfg, NULL);
// 启用 BLE
nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ble_cfg);
nrf_sdh_ble_enable(&ram_start);
// 配置广播参数
ble_gap_adv_params_t adv_params = {
.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED,
.interval.min = 160, // 100ms
.interval.max = 160,
};
sd_ble_gap_adv_start(&adv_params, APP_BLE_CONN_CFG_TAG);
}