蓝牙协议栈

从软件开发者角度理解蓝牙协议栈,掌握各层职责、数据包结构和 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

📋 各层职责与开发接口

图表总览

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

各层详细说明

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

开发者关注点

职责 开发者接口 典型 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);
}