ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

esp-iot-solution 的 BLE HCI 组件:绕过协议栈、通过 VHCI 直控 BLE Controller 实现广播与扫描

esp-iot-solution 的 BLE HCI 组件:绕过协议栈、通过 VHCI 直控 BLE Controller 实现广播与扫描 esp-iot-solution 的 BLE HCI 组件绕过协议栈、通过 VHCI 直控 BLE Controller 实现广播与扫描【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution导读BLE HCI 组件是 esp-iot-solution 提供的一个轻量级蓝牙组件它绕过 Nimble / Bluedroid 完整协议栈通过 Espressif 的 VHCIVirtual Host Controller Interface接口直接向 BLE Controller 下发 HCI 命令实现广播Advertising与扫描Scanning等最常用的 BLE 功能。读完本文你将掌握该组件的架构原理、广播与扫描两条完整调用链路、全部公开 API 的参数含义与取值范围并能够基于仓库中的单元测试示例在自有项目里快速集成。组件定位为什么需要绕过协议栈官方文档 BLE HCI 组件说明 明确指出该组件用于通过 VHCI 接口直接操作 BLE Controller 实现广播、扫描等功能。与通过 Nimble 或 Bluedroid 协议栈发起广播和扫描相比使用该组件有如下优点更少的内存占用不加载完整 Host 协议栈组件内部仅维护两条 FreeRTOS 队列与一个事件处理任务更小的固件尺寸不链接协议栈代码只编译 ble_hci.c 与 bt_hci_common.c 两个源文件更快的初始化流程初始化时只需esp_bt_controller_initesp_bt_controller_enable无需等待 Host 协议栈启动。从 README_CN.md 的支持指令列表看组件聚焦于四类能力发送广播包、扫描广播包、白名单Filter Accept List以及设置本地地址。这正是传感器节点、信标Beacon、网关等只要广播和扫描、不需要 GATT 连接场景的典型诉求。底层架构VHCI 回调、命令封装与事件处理任务VHCI 回调注册组件初始化时通过esp_vhci_host_register_callback注册一组回调见 ble_hci.cstatic esp_vhci_host_callback_t vhci_host_cb { controller_rcv_pkt_ready, host_rcv_pkt };controller_rcv_pkt_ready当 Controller 可以接收新数据时被调用host_rcv_pkt当 Controller 有事件包HCI Event上送时被调用数据会拷贝后投递到hci_data_queue队列。HCI 命令的构造与下发所有命令都不是直接调用某个封装好的 API而是由 bt_hci_common.c 中的make_cmd_*系列函数按 HCI 规范手工拼装命令包再通过esp_vhci_host_send_packet发送。命令包遵循 H4 传输层格式第 1 字节为 H4 类型命令为0x01随后是 2 字节 Opcode 与 1 字节参数长度之后是参数体。以设置广播参数为例uint16_t make_cmd_ble_set_adv_param(uint8_t *buf, uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type, uint8_t addr_type_own, uint8_t addr_type_dir, bd_addr_t direct_bda, uint8_t channel_map, uint8_t adv_filter_policy)对应的 OCF/OGF 定义位于 bt_hci_common.h例如HCI_BLE_WRITE_ADV_PARAMSOGF0x08, OCF0x0006参数 15 字节HCI_BLE_WRITE_ADV_DATAOCF0x0008参数上限 31 字节HCI_BLE_WRITE_ADV_ENABLEOCF0x000AHCI_BLE_WRITE_SCAN_PARAMOCF0x000B参数 7 字节HCI_BLE_WRITE_SCAN_ENABLEOCF0x000C参数 2 字节HCI_BLE_SET_RANDOM_ADDROCF0x0005参数 6 字节HCI_BLE_ADD_TO_ACCEPT_LIST/HCI_BLE_CLEAR_ACCEPT_LISTOCF0x0011 / 0x0010HCI_SET_EVT_MASKOGF0x03, OCF0x00018 字节事件掩码命令同步等待机制每条命令下发后组件会等待对应的 HCI Command Complete 事件。事件处理任务从hci_cmd_evt_queue中取出响应并校验 Opcode 与返回状态reason超时时间固定为CMD_WAIT_TIME (100/portTICK_PERIOD_MS)。状态码0表示成功非零值会通过ESP_LOGE打印失败原因ble_hci.c。事件处理任务从裸字节到结构化结果初始化时会创建一个名为hci_evt_process、优先级 6、栈 2048 字节、固定核 0 的任务ble_hci.c。它循环从hci_data_queue取包并解析若事件 Opcode 为0x3ELE Meta Events继续读 Sub Event当 Sub Event 为0x02LE Advertising Report时依次解析设备地址类型、6 字节地址、广播数据长度与内容、扫描响应长度与内容并把 RSSI 由无符号值转换为负数s_ble_hci-scan_result[i].rssi -(0xFF - queue_data[data_ptr]);若事件 Opcode 为0x0ECommand Complete则把命令 Opcode 与 reason 投递到hci_cmd_evt_queue供下发命令的 API 同步等待其他事件一律打印 Unhandled HCI event code 告警。扫描结果缓冲区上限为SCAN_RESULT_LEN_MAX 25条每条结果保存在ble_hci_scan_result_t中解析完成后一次性回调给注册的扫描回调函数。广播应用五步完成一次 BLE 广播根据 BLE HCI 组件说明 的广播流程典型调用顺序为调用ble_hci_init()初始化 2.可选调用ble_hci_set_random_address()设置本地随机地址调用ble_hci_set_adv_param()配置广播参数调用ble_hci_set_adv_data()设定广播数据调用ble_hci_set_adv_enable(true)开启广播。仓库中的单元测试 ble_hci_test.c 给出了完整的可运行示例ble_hci_init(); uint8_t own_addr[6] {0xff, 0x22, 0x33, 0x44, 0x55, 0x66}; ble_hci_set_random_address(own_addr); ble_hci_adv_param_t adv_param { .adv_int_min 0x20, .adv_int_max 0x40, .adv_type ADV_TYPE_NONCONN_IND, .own_addr_type BLE_ADDR_TYPE_RANDOM, .peer_addr_type BLE_ADDR_TYPE_PUBLIC, .channel_map ADV_CHNL_ALL, .adv_filter_policy ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; uint8_t peer_addr[6] {0x80, 0x81, 0x82, 0x83, 0x84, 0x85}; memcpy(adv_param.peer_addr, peer_addr, BLE_HCI_ADDR_LEN); ble_hci_set_adv_param(adv_param); char *adv_name ESP-BLE-1; uint8_t name_len (uint8_t)strlen(adv_name); uint8_t adv_data[31] { 0x02, 0x01, 0x06, 0x0, 0x09 }; adv_data[3] name_len 1; memcpy(adv_data 5, adv_name, name_len); ble_hci_set_adv_data(5 name_len, adv_data); ble_hci_set_adv_enable(true); // ... 广播 5 秒 ... ble_hci_set_adv_enable(false); ble_hci_deinit();测试中构造的广播数据含义0x02 0x01 0x06为 Flags 段LE General Discoverable BR/EDR Not Supported0x09为 Complete Local Name 类型随后紧跟设备名 ESP-BLE-1其数据段组装方式完全遵循 BLE 广播数据 AD Structure 格式。广播参数详解ble_hci_adv_param_t各字段定义与取值范围见 ble_hci.h字段含义取值范围/说明adv_int_min/adv_int_max广播间隔上下限实际时间 N × 0.625 ms范围 0x0020 ~ 0x4000即 20 ms ~ 10.24 sadv_type广播类型ADV_TYPE_IND(0x00) 可连接可扫描、ADV_TYPE_DIRECT_IND_HIGH(0x01) 高占空比定向、ADV_TYPE_SCAN_IND(0x02) 可扫描、ADV_TYPE_NONCONN_IND(0x03) 不可连接、ADV_TYPE_DIRECT_IND_LOW(0x04) 低占空比定向own_addr_type本机地址类型BLE_ADDR_TYPE_PUBLIC(0x00) /BLE_ADDR_TYPE_RANDOM(0x01) / RPA 类型0x02/0x03peer_addr/peer_addr_type对端地址及类型仅定向广播Direct时使用类型只支持 public/randomchannel_map广播信道ADV_CHNL_37(0x01) /ADV_CHNL_38(0x02) /ADV_CHNL_39(0x04) /ADV_CHNL_ALL(0x07)adv_filter_policy广播过滤策略ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY(0x00) 等四种组合控制扫描请求与连接请求是否只接受白名单设备广播数据上限广播数据最大长度为ESP_BLE_ADV_DATA_LEN_MAX 31字节扫描响应数据同样为 31 字节ble_hci.h。ble_hci_set_adv_data(len, data)内部在构造命令时会做截断保护当传入长度超过 31 字节时按 31 字节处理见 bt_hci_common.c。扫描应用五步注册回调并开始扫描根据 BLE HCI 组件说明 的扫描流程典型调用顺序为调用ble_hci_init()初始化调用ble_hci_set_scan_param()配置扫描参数调用ble_hci_enable_meta_event()使能 LE Meta 事件调用ble_hci_set_register_scan_callback()注册扫描回调调用ble_hci_set_scan_enable(true, filter_duplicates)开始扫描。仓库测试用例 ble_hci_test.c 的扫描部分同样可以直接套用ble_hci_init(); ble_hci_reset(); ble_hci_enable_meta_event(); ble_hci_scan_param_t scan_param { .scan_type BLE_SCAN_TYPE_PASSIVE, .scan_interval 0x50, .scan_window 0x50, .own_addr_type BLE_ADDR_TYPE_PUBLIC, .filter_policy ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY, }; ble_hci_set_scan_param(scan_param); ble_hci_set_register_scan_callback(ble_hci_scan_cb); uint8_t peer_addr[6] {0xff, 0x22, 0x33, 0x44, 0x55, 0x66}; ble_hci_add_to_accept_list(peer_addr, BLE_ADDR_TYPE_RANDOM); ble_hci_set_scan_enable(true, false); // ... 扫描 5 秒回调中打印结果 ... ble_hci_set_scan_enable(false, false); ble_hci_deinit();回调函数签名如下result_len表示本次上报的扫描结果条数最多 25 条static void ble_hci_scan_cb(ble_hci_scan_result_t *scan_result, uint16_t result_len) { for (int i 0; i result_len; i) { printf(%2x:%2x:%2x:%2x:%2x:%2x\n, scan_result[i].bda[0], scan_result[i].bda[1], scan_result[i].bda[2], scan_result[i].bda[3], scan_result[i].bda[4], scan_result[i].bda[5]); } }扫描参数详解ble_hci_scan_param_t字段ble_hci.h字段含义取值范围/说明scan_type扫描类型BLE_SCAN_TYPE_PASSIVE(0x0) 被动扫描 /BLE_SCAN_TYPE_ACTIVE(0x1) 主动扫描会发送扫描请求以获取扫描响应数据scan_interval扫描间隔实际时间 N × 0.625 ms范围 0x0004 ~ 0x4000即 2.5 ms ~ 10.24 sscan_window扫描窗口同样按 0.625 ms 换算范围 0x0004 ~ 0x4000且应不大于 scan_intervalown_addr_type本机地址类型同广播参数filter_policy扫描过滤策略复用ble_hci_adv_filter_t枚举决定是否只接收白名单设备使能 Meta 事件的关键一步ble_hci_enable_meta_event()的作用是向 Controller 发送HCI_SET_EVT_MASK命令把 8 字节事件掩码的第 61 位置 1掩码{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20}从而打开 LE Meta Events 通道ble_hci.c。漏掉这一步扫描回调将永远收不到广告上报事件这也是扫描流程与广播流程最大的差异点。扫描结果结构每个扫描结果ble_hci_scan_result_tble_hci.h包含search_evt搜索事件类型查询结果、发现结果、完成等dev_type设备类型BR/EDR、BLE、双模bda6 字节对端地址ble_addr_type对端地址类型ble_adv[62]接收到的完整 EIR广播数据 扫描响应数据各最多 31 字节adv_data_len/scan_rsp_len广播数据与扫描响应长度rssi信号强度负数单位为 dBm。白名单与随机地址精细化控制手段ble_hci_add_to_accept_list(addr, addr_type)把单个设备加入 Controller 内部的 Filter Accept List白名单地址类型 0x00 为 public、0x01 为 random对应 HCI 命令参数长度为 7 字节1 字节类型 6 字节地址。ble_hci_clear_accept_list()清空白名单。ble_hci_set_random_address(addr)设置本机随机地址。使用随机地址作为广播地址时需要在配置广播参数前调用并把own_addr_type设置为BLE_ADDR_TYPE_RANDOM。白名单与广播/扫描的过滤策略adv_filter_policy配合使用即可实现只对特定设备可见/只扫描特定设备的定向广播与定向扫描。完整 API 参考组件的全部公开 API 定义在 ble_hci.h文档中的 API 参考 一节即由该头文件自动生成。按功能归类如下API功能ble_hci_init()初始化创建队列与事件任务、初始化并使能 BLE Controller、注册 VHCI 回调ble_hci_deinit()反初始化删除任务、禁用并反初始化 Controller、释放队列与内存ble_hci_reset()复位 Controllerble_hci_set_random_address(addr)设置本机随机地址ble_hci_set_adv_param(param)设置广播参数ble_hci_set_adv_data(len, data)设置广播数据≤ 31 字节ble_hci_set_adv_enable(enable)开启/关闭广播ble_hci_enable_meta_event()使能 LE Meta 事件扫描前必调ble_hci_set_scan_param(param)设置扫描参数ble_hci_set_scan_enable(enable, filter_duplicates)开启/关闭扫描可同时决定是否过滤重复设备ble_hci_set_register_scan_callback(cb)注册扫描结果回调ble_hci_add_to_accept_list(addr, addr_type)向白名单添加设备ble_hci_clear_accept_list()清空白名单除ble_hci_set_register_scan_callback与ble_hci_init/ble_hci_deinit外各命令类 API 均返回 HCI Command Complete 事件的 reason 字段0表示成功底层统一通过hci_cmd_evt_queue同步等待因此不要并发调用多条命令以免阻塞在 100 ms 的超时等待上。在项目中集成与验证组件以标准 IDF 组件形式组织CMakeLists.txt核心依赖仅为btREQUIRES bt。从 idf_component.yml 可以确认其依赖约束为idf: 5.0并依赖cmake_utilities: 0.*因此适用于 ESP-IDF 5.0 及以上版本。既可以将 components/bluetooth/ble_hci 目录整体放入自己工程的components/下作为本地组件也可以通过 ESP Component Registry 按组件方式拉取。组件自带完整测试工程 test_apps/main/ble_hci_test.c基于 Unity 框架提供[ble hci adv]与[ble hci scan]两个测试用例分别覆盖广播与扫描全流程并在setUp/tearDown中通过heap_caps_get_free_size对比 8-bit/32-bit 堆内存差值阈值 -460 字节来校验 init/deinit 循环后无内存泄漏。参考该测试文件即可快速搭建自己的 demo先在app_main中调用unity_run_menu()再按上文步骤在测试用例中完成广播或扫描链路。结语BLE HCI 组件把广播 扫描这一最常用的 BLE 能力压缩到一个轻量组件中相比 Nimble/Bluedroid 全协议栈它以更少内存、更小固件、更快初始化的方式满足了信标、传感节点、网关等场景需求相比裸写 VHCI 回调它又提供了ble_hci_*一套同步、简洁、参数完备的封装并自带可验证的测试用例。需要进一步了解组件设计与枚举细节时可直接阅读 ble_hci.h 与 ble_hci.c 的完整实现。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表