BLE扫描器API¶
本文档引用的文件 - ble_scanner.c - ble_scanner.h - hci_transport.h - config.h - main.c - hci_test_server.c
目录¶
简介¶
BLE扫描器组件是一个基于ESP32-S3的蓝牙低功耗网关系统的核心模块,负责通过外部NRF52833控制器进行BLE设备扫描、管理和连接。该组件实现了完整的BLE扫描功能,包括设备发现、扫描控制、设备过滤和状态查询等核心接口。
本组件采用分层架构设计,通过HCI传输层与外部BLE控制器通信,内部维护设备列表和连接状态,并提供丰富的回调机制来通知上层应用设备状态变化。
项目结构¶
BLE扫描器组件位于项目的old_version/components/ble_scanner目录下,主要包含以下文件:
graph TB
subgraph "BLE扫描器组件"
A[ble_scanner.c<br/>主实现文件]
B[ble_scanner.h<br/>接口定义文件]
end
subgraph "相关头文件"
C[hci_transport.h<br/>HCI传输层接口]
D[config.h<br/>配置常量定义]
E[main.h<br/>主程序入口]
end
subgraph "测试工具"
F[hci_test_server.c<br/>HCI测试服务器]
end
A --> B
A --> C
A --> D
E --> A
F --> C
图表来源 - ble_scanner.c - ble_scanner.h
章节来源 - ble_scanner.c - ble_scanner.h
核心组件¶
BLE扫描器组件由多个核心组件构成,每个组件都有明确的职责分工:
数据结构组件¶
组件使用多种数据结构来管理BLE设备信息和扫描参数:
- 设备信息结构体: 存储单个BLE设备的完整信息
- 扫描参数结构体: 配置BLE扫描行为
- 设备过滤器结构体: 定义设备筛选条件
- 连接信息结构体: 跟踪当前BLE连接状态
回调机制组件¶
组件提供了两种类型的回调机制:
- 设备发现回调: 当新设备被发现时触发
- 连接状态回调: 当BLE连接状态发生变化时触发
扫描控制组件¶
组件实现了完整的BLE扫描控制功能:
- 初始化/去初始化: 设置硬件和配置参数
- 启动/停止扫描: 控制扫描生命周期
- 参数配置: 动态调整扫描行为
- 设备管理: 维护设备列表和状态
章节来源 - ble_scanner.h - ble_scanner.c
架构概览¶
BLE扫描器采用分层架构设计,确保了良好的模块化和可维护性:
graph TB
subgraph "应用层"
A[主应用程序<br/>main.c]
B[WebUI服务器<br/>webui_server.c]
C[MQTT客户端<br/>mqtt_client_wrapper.c]
end
subgraph "BLE扫描器层"
D[BLE扫描器<br/>ble_scanner.c]
E[设备管理<br/>设备列表/过滤]
F[连接管理<br/>连接状态跟踪]
end
subgraph "传输层"
G[HCI传输层<br/>hci_transport.c]
H[UART通信<br/>NRF52833控制器]
end
subgraph "硬件层"
I[ESP32-S3主控制器]
J[NRF52833外部BLE控制器]
end
A --> D
B --> D
C --> D
D --> E
D --> F
D --> G
G --> H
H --> I
H --> J
图表来源 - main.c - ble_scanner.c - hci_transport.h
详细组件分析¶
设备发现与管理¶
BLE扫描器的核心功能是发现和管理BLE设备。系统通过以下机制实现:
广告数据解析¶
组件能够解析BLE设备的广告数据,提取关键信息:
flowchart TD
A[接收广告数据] --> B{数据长度有效?}
B --> |否| C[忽略数据]
B --> |是| D[解析数据字段]
D --> E{找到名称字段?}
E --> |是| F[提取设备名称]
E --> |否| G[继续解析其他字段]
F --> H[更新设备信息]
G --> H
H --> I[检查过滤条件]
I --> J{通过过滤?}
J --> |是| K[触发设备回调]
J --> |否| L[忽略设备]
K --> M[更新设备列表]
L --> M
M --> N[更新最后出现时间]
图表来源 - ble_scanner.c - ble_scanner.c
设备列表管理¶
系统维护一个固定大小的设备列表,支持动态添加、更新和清理:
- 最大设备数量: 100个设备
- 自动清理: 超过60秒未出现的设备会被移除
- 线程安全: 使用互斥锁保护设备列表访问
- 重复过滤: 可选择过滤重复的广告包
章节来源 - ble_scanner.c - config.h
扫描控制接口¶
BLE扫描器提供了完整的扫描控制API:
初始化和去初始化¶
sequenceDiagram
participant App as 应用程序
participant Scanner as BLE扫描器
participant Transport as HCI传输层
participant Controller as NRF52833控制器
App->>Scanner : ble_scanner_init()
Scanner->>Transport : 注册事件回调
Scanner->>Transport : 发送设置事件掩码命令
Transport->>Controller : HCI_Set_Event_Mask
Controller-->>Transport : 命令完成事件
Scanner->>Transport : 发送LE事件掩码命令
Transport->>Controller : HCI_LE_Set_Event_Mask
Controller-->>Transport : 命令完成事件
Scanner->>Transport : 发送随机地址命令
Transport->>Controller : HCI_LE_Set_Random_Address
Controller-->>Transport : 命令完成事件
Scanner-->>App : 初始化完成
图表来源 - ble_scanner.c - hci_transport.h
扫描参数配置¶
扫描参数通过ble_scan_params_t结构体配置:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| scan_interval | uint16_t | 扫描间隔(0.625ms单位) | 0x0050 (50ms) |
| scan_window | uint16_t | 扫描窗口(0.625ms单位) | 0x0030 (30ms) |
| scan_type | uint8_t | 扫描类型(0=被动,1=主动) | 0x01 (主动) |
| filter_policy | uint8_t | 过滤策略 | 0x00 (接受所有) |
| filter_duplicates | bool | 是否过滤重复 | true |
章节来源 - ble_scanner.h - config.h
设备过滤机制¶
BLE扫描器支持多维度的设备过滤:
flowchart TD
A[设备到达] --> B[RSSI过滤]
B --> C{RSSI >= 阈值?}
C --> |否| D[拒绝设备]
C --> |是| E[名称过滤]
E --> F{名称匹配?}
F --> |否| D
F --> |是| G[MAC地址过滤]
G --> H{MAC匹配?}
H --> |否| D
H --> |是| I[接受设备]
D --> J[设备被拒绝]
I --> K[触发回调]
K --> L[更新设备列表]
图表来源 - ble_scanner.c
过滤器配置通过ble_device_filter_t结构体实现:
| 字段 | 类型 | 描述 |
|---|---|---|
| name_filter | char[] | 名称包含过滤字符串 |
| rssi_filter | int8_t | 最小RSSI阈值 |
| mac_filter | uint8_t[6] | MAC地址过滤 |
| mac_filter_enabled | bool | 是否启用MAC过滤 |
章节来源 - ble_scanner.h
连接管理功能¶
BLE扫描器不仅支持扫描,还提供了基本的BLE连接管理:
连接状态管理¶
连接状态通过ble_conn_state_t枚举管理:
stateDiagram-v2
[*] --> 断开连接
断开连接 --> 连接中 : ble_scanner_connect()
连接中 --> 已连接 : 连接成功事件
连接中 --> 断开连接 : 连接失败事件
已连接 --> 断开连接 : disconnect() 或断开事件
图表来源 - ble_scanner.h
连接参数配置¶
连接参数通过ble_connection_t结构体跟踪:
| 字段 | 类型 | 描述 |
|---|---|---|
| conn_handle | uint16_t | 连接句柄 |
| peer_addr | uint8_t[6] | 对端设备地址 |
| peer_addr_type | uint8_t | 对端地址类型 |
| state | ble_conn_state_t | 当前连接状态 |
| conn_interval | uint16_t | 连接间隔 |
| conn_latency | uint16_t | 连接延迟 |
| supervision_timeout | uint16_t | 监督超时 |
章节来源 - ble_scanner.h
回调机制与事件处理¶
BLE扫描器提供了灵活的回调机制来通知上层应用状态变化:
设备发现回调¶
当新设备被发现且通过过滤条件时,会触发设备发现回调:
sequenceDiagram
participant Controller as BLE控制器
participant Scanner as BLE扫描器
participant Callback as 用户回调
participant App as 应用程序
Controller->>Scanner : LE_Advertising_Report事件
Scanner->>Scanner : 解析广告数据
Scanner->>Scanner : 检查过滤条件
alt 设备通过过滤
Scanner->>Callback : 调用设备回调
Callback->>App : 处理设备信息
else 设备被拒绝
Scanner->>Scanner : 忽略设备
end
图表来源 - ble_scanner.c
连接状态回调¶
连接状态变化时触发连接状态回调:
sequenceDiagram
participant Controller as BLE控制器
participant Scanner as BLE扫描器
participant ConnCallback as 连接回调
participant App as 应用程序
Controller->>Scanner : LE_Connection_Complete事件
Scanner->>Scanner : 更新连接状态
Scanner->>ConnCallback : 调用连接回调
ConnCallback->>App : 处理连接状态
图表来源 - ble_scanner.c
章节来源 - ble_scanner.h - ble_scanner.h
依赖关系分析¶
BLE扫描器组件的依赖关系清晰明确,遵循了良好的软件工程原则:
graph TB
subgraph "外部依赖"
A[ESP-IDF框架]
B[FREERTOS]
C[ESP_LOG宏]
end
subgraph "组件内部依赖"
D[ble_scanner.c]
E[ble_scanner.h]
F[hci_transport.h]
G[config.h]
end
subgraph "硬件依赖"
H[ESP32-S3主控制器]
I[NRF52833外部BLE控制器]
J[UART接口]
end
D --> E
D --> F
D --> G
E --> F
E --> G
D --> A
D --> B
D --> C
F --> H
F --> J
F --> I
图表来源 - ble_scanner.c - hci_transport.h
关键依赖说明¶
- ESP-IDF框架: 提供底层硬件抽象和系统服务
- FreeRTOS: 提供任务调度和同步原语
- HCI传输层: 抽象了与BLE控制器的通信协议
- 配置常量: 定义了硬件特性和运行参数
章节来源 - ble_scanner.c - config.h
性能考虑¶
BLE扫描器在设计时充分考虑了性能优化:
内存管理¶
- 静态分配: 设备列表使用静态数组,避免动态内存分配带来的碎片化
- 固定大小: 最大设备数量限制为100个,确保内存使用可预测
- 自动清理: 超时设备自动移除,防止内存泄漏
扫描效率¶
- 重复过滤: 启用重复过滤减少不必要的回调触发
- 批量处理: 设备列表操作使用互斥锁保护,避免竞态条件
- 异步处理: 通过回调机制实现非阻塞的事件处理
资源优化¶
- 线程安全: 使用互斥锁保护共享资源
- 最小化阻塞: 扫描操作非阻塞,不影响其他任务执行
- 硬件优化: 利用外部BLE控制器减轻主控制器负担
故障排除指南¶
常见问题及解决方案¶
扫描无法启动¶
症状: 调用ble_scanner_start()返回错误
可能原因: 1. HCI传输层未正确初始化 2. 设备处于已连接状态 3. 扫描参数配置无效
解决方法:
// 检查初始化状态
if (ble_scanner_init() != ESP_OK) {
ESP_LOGE(TAG, "BLE扫描器初始化失败");
return;
}
// 确保设备处于断开连接状态
ble_connection_t conn;
if (ble_scanner_get_connection(&conn) == ESP_OK) {
if (conn.state == BLE_CONN_STATE_CONNECTED) {
ble_scanner_disconnect(0);
}
}
// 启动扫描
if (ble_scanner_start() != ESP_OK) {
ESP_LOGE(TAG, "BLE扫描启动失败");
}
设备过滤不生效¶
症状: 设置过滤器后仍能收到不符合条件的设备
可能原因: 1. 过滤器配置未正确设置 2. 设备名称解析失败 3. 回调函数未正确注册
解决方法:
// 正确设置过滤器
ble_device_filter_t filter = {0};
strcpy(filter.name_filter, "MyDevice");
filter.rssi_filter = -80; // 设置RSSI阈值
filter.mac_filter_enabled = false;
if (ble_scanner_set_filter(&filter) != ESP_OK) {
ESP_LOGE(TAG, "设置过滤器失败");
}
内存不足错误¶
症状: ESP_ERR_NO_MEM错误
可能原因: 1. 设备列表已满 2. 互斥锁创建失败 3. 内存碎片化
解决方法:
// 清理设备列表
ble_scanner_clear_devices();
// 检查可用内存
ESP_LOGI(TAG, "可用堆内存: %lu bytes", esp_get_free_heap_size());
// 重新初始化
ble_scanner_deinit();
ble_scanner_init();
章节来源 - ble_scanner.c - ble_scanner.c
结论¶
BLE扫描器组件是一个功能完整、设计合理的嵌入式BLE管理模块。它通过清晰的分层架构、完善的API设计和高效的实现方式,为ESP32-S3 BLE网关系统提供了强大的BLE设备管理能力。
组件的主要优势包括: - 模块化设计: 良好的职责分离和接口抽象 - 性能优化: 静态内存分配和高效的算法实现 - 易用性: 直观的API和丰富的回调机制 - 可靠性: 完善的错误处理和状态管理
对于开发者而言,该组件提供了清晰的扩展点和良好的集成接口,可以轻松地集成到各种BLE应用场景中。
附录¶
API参考表¶
设备发现相关API¶
| 函数名 | 参数 | 返回值 | 描述 |
|---|---|---|---|
ble_scanner_init() |
无 | esp_err_t |
初始化BLE扫描器 |
ble_scanner_deinit() |
无 | esp_err_t |
去初始化BLE扫描器 |
ble_scanner_start() |
无 | esp_err_t |
开始BLE扫描 |
ble_scanner_stop() |
无 | esp_err_t |
停止BLE扫描 |
ble_scanner_register_callback() |
ble_device_callback_t |
esp_err_t |
注册设备回调 |
设备管理相关API¶
| 函数名 | 参数 | 返回值 | 描述 |
|---|---|---|---|
ble_scanner_get_devices() |
ble_device_t[], uint8_t, uint8_t* |
esp_err_t |
获取设备列表 |
ble_scanner_clear_devices() |
无 | esp_err_t |
清空设备列表 |
ble_scanner_get_device_count() |
无 | uint8_t |
获取设备数量 |
ble_scanner_is_running() |
无 | bool |
检查扫描状态 |
连接管理相关API¶
| 函数名 | 参数 | 返回值 | 描述 |
|---|---|---|---|
ble_scanner_connect() |
uint8_t*, uint8_t |
esp_err_t |
连接到BLE设备 |
ble_scanner_disconnect() |
uint16_t |
esp_err_t |
断开BLE连接 |
ble_scanner_get_connection() |
ble_connection_t* |
esp_err_t |
获取连接信息 |
ble_scanner_register_conn_callback() |
ble_conn_callback_t |
void |
注册连接回调 |
错误码定义¶
BLE扫描器使用标准的ESP-IDF错误码:
ESP_OK: 操作成功ESP_ERR_INVALID_ARG: 参数无效ESP_ERR_INVALID_STATE: 状态无效ESP_ERR_NO_MEM: 内存不足ESP_ERR_NOT_FOUND: 未找到目标ESP_ERR_TIMEOUT: 操作超时
使用示例¶
以下是一个完整的BLE扫描器使用示例:
// 初始化BLE扫描器
if (ble_scanner_init() != ESP_OK) {
ESP_LOGE(TAG, "BLE扫描器初始化失败");
return;
}
// 设置设备过滤器
ble_device_filter_t filter = {0};
strcpy(filter.name_filter, "MyDevice");
filter.rssi_filter = -80;
ble_scanner_set_filter(&filter);
// 注册回调函数
ble_scanner_register_callback(on_device_found);
// 开始扫描
ble_scanner_start();
// 主循环
while (1) {
// 获取设备列表
ble_device_t devices[MAX_DEVICES];
uint8_t count;
if (ble_scanner_get_devices(devices, MAX_DEVICES, &count) == ESP_OK) {
for (int i = 0; i < count; i++) {
printf("设备: %s (RSSI: %d)\n", devices[i].name, devices[i].rssi);
}
}
vTaskDelay(pdMS_TO_TICKS(1000));
}