协议栈架构
`
┌─────────────────────────────────────────┐
│ 应用层 (Application) │
├─────────────────────────────────────────┤
│ GATT (通用属性配置文件) │
├─────────────────────────────────────────┤
│ ATT (属性协议) │
├─────────────────────────────────────────┤
│ SMP (安全管理) │
├─────────────────────────────────────────┤
│ L2CAP (逻辑链路控制) │
├─────────────────────────────────────────┤
│ HCI (主机控制接口) │
├─────────────────────────────────────────┤
│ 控制器 (Controller) │
└─────────────────────────────────────────┘
`
GAP层
GAP角色
| 角色 | 说明 |
|---|---|
| Central | 主机,扫描连接 |
| Peripheral | 从机,广播 |
| Observer | 观察者,扫描 |
| Broadcaster | 广播者,广播 |
广播类型
可连接广播:
- 允许被连接
- 用于从机设备
不可连接广播:
- 仅广播数据
- 用于Beacon
定向广播:
- 快速连接特定设备
ATT层
ATT角色
| 角色 | 说明 |
|---|---|
| Server | 提供属性 |
| Client | 访问属性 |
属性类型
`
属性 = 属性句柄 + 属性类型 + 属性值 + 属性权限
示例:
句柄: 0x0001
类型: 0x2803 (Characteristic)
值: 0xFFE1 (自定义UUID)
权限: Read/Write
`
ATT操作
| 操作 | 说明 |
|---|---|
| Find Information | 查询属性信息 |
| Read | 读取属性值 |
| Write | 写入属性值 |
| Notifications | 服务器主动通知 |
| Indications | 服务器指示(需确认) |
GATT层
GATT角色
| 角色 | 说明 |
|---|---|
| Server | 服务端 |
| Client | 客户端 |
服务结构
`
服务 (Service)
│
├── 主服务UUID
│
├── 包含声明 (Include)
│
└── 特征 (Characteristic)
│
├── 特征声明
│ • 属性类型
│ • 属性句柄
│ • 权限
│
└── 特征值 (Value)
• 实际数据
• UUID
• 权限
└── 描述符 (Descriptor)
• 客户端配置
• 描述信息
• 格式化
`
标准服务
| 服务 | UUID | 说明 |
|---|---|---|
| Generic Access | 0x1800 | 通用访问 |
| Generic Attribute | 0x1801 | 通用属性 |
| Device Information | 0x180A | 设备信息 |
| Battery Service | 0x180F | 电池服务 |
| Heart Rate | 0x180D | 心率服务 |
自定义服务
`c
// 自定义服务UUID
#define CUSTOM_SERVICE_UUID 0xFFE0
// 自定义特征UUID
#define CUSTOM_CHAR_UUID 0xFFE1
// 服务定义
ble_gatt_srv_def_t custom_service = {
.type = BLE_GATT_SRV_TYPE_PRIMARY,
.uuid.uuid = CUSTOM_SERVICE_UUID,
.characteristics = {
{
.characteristic = {
.uuid.uuid = CUSTOM_CHAR_UUID,
.properties = BLE_GATT_CHR_PROPS_READ |
BLE_GATT_CHR_PROPS_WRITE |
BLE_GATT_CHR_PROPS_NOTIFY,
.permissions = BLE_GATT_PERM_READ |
BLE_GATT_PERM_WRITE
},
.value = {
.len = 20,
.data = custom_value
}
},
{ 0 }
}
};
`
特征值操作
读取
客户端请求:
`c
// 读取特征值
ble_gatt_read(handle, char_handle);
`
服务器响应:
`c
// 读取响应回调
void on_read_request(uint16_t conn_handle,
uint16_t attr_handle,
uint16_t offset) {
// 返回数据
ble_gatt_read_rsp(conn_handle, attr_handle,
data, len);
}
`
写入
写入请求:
`c
// 写入特征值
ble_gatt_write(handle, char_handle,
data, len);
`
写入响应:
`c
// 写入响应回调
void on_write_request(uint16_t conn_handle,
uint16_t attr_handle,
uint8_t *data,
uint16_t len) {
// 处理数据
process_data(data, len);
// 发送响应
ble_gatt_write_rsp(conn_handle, BLE_GATT_STATUS_SUCCESS);
}
`
通知
服务器主动通知:
`c
// 发送通知
ble_gatt_notify(conn_handle,
char_handle,
data, len);
`
客户端配置:
`c
// 客户端配置通知
uint16_t client_config = 0x0001; // 启用通知
ble_gatt_write(handle,
cccd_handle,
&client_config, 2);
`
客户端配置描述符 (CCCD)
CCCD定义
| 位 | 说明 |
|---|---|
| ---- | ------ |
| 0 | 通知 (Notifications) |
| 1 | 指示 (Indications) |
使用示例
`c
// CCCD特征
// UUID: 0x2902
// 启用通知
uint16_t cccd_value = 0x0001;
ble_gatt_write(conn_handle,
cccd_handle,
&cccd_value, sizeof(cccd_value));
// 禁用通知
cccd_value = 0x0000;
ble_gatt_write(conn_handle,
cccd_handle,
&cccd_value, sizeof(cccd_value));
`
安全机制
认证级别
| 级别 | 要求 |
|---|---|
| Open | 无安全要求 |
| Just Works | 无需MITM |
| Passkey Entry | 输入密钥 |
| OOB | 外部密钥 |
加密流程
`
1. 配对请求
2. 密钥交换
3. 绑定存储
4. 链路加密
`
常见UUID
服务UUID
| 服务 | UUID |
|---|---|
| 设备信息 | 0x180A |
| 电池 | 0x180F |
| 心率 | 0x180D |
| 扫描参数 | 0x1813 |
特征UUID
| 特征 | UUID |
|---|---|
| 设备名称 | 0x2A00 |
| 外观 | 0x2A01 |
| 电池电量 | 0x2A19 |
| 心率测量 | 0x2A37 |
调试工具
手机APP
- nRF Connect
- LightBlue
- BLE Scanner
电脑工具
- Nordic nRF Sniffer
- Wireshark + BTVS
- TI Sniffer