HCI 简介
BLE 协议栈分为 Host 和 Controller 两大部分,通过 HCI (Host Controller Interface) 进行相互通讯,而 HCI 硬件传输接口又分为多种,包括 USB、UART 和 SDIO 等。 在 esp-idf 中 Host 分为 bluedroid 和 nimble, 相关的一些应用例程也在 bluedroid 和 nimble 目录下,同时 esp-idf 也提供了不使用以上两个 Host 仅使用芯片 BT Controller 的例程,以满足使用者的其他需求,如 Host 协议栈运行在其他 MCU 上仅需要一个 BT Controller 硬件,或者作为一个 PC 机上的蓝牙适配器的功能
如下来介绍 在 Linux 系统上 esp 芯片的一些 HCI 例程的使用
BlueZ 的安装和使用
-
BlueZ 版本查看
BlueZ 是 linux 官方蓝牙协议栈,一般在 linux 系统都会自带,使用以下指令查看 BlueZ 版本
$ dpkg -s bluez |grep ^Version Version: 5.53-0ubuntu3.5
BlueZ 的安装或更新可参考以下文章或自行搜索:Ubuntu 20.04编译安装BlueZ-5.6
-
hciattch 的使用
hciattch 用于把串行 UART 挂载为 HCI 传输接口,与 BlueZ 协议栈进行通讯,命令格式如下
hciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [sleep|nosleep] [bdaddr] -n 不脱离控制终端 -p 当脱离时打印 PID -t 指定初始化超时时间,默认5秒 tty 指定要挂在的串口设备,可以省略 /dev/ 前导 type|id 一般是 any, 不指定厂商等 speed 一般支持以下速度 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 flow 使用硬件流量控制, noflow不使用 sleep|nosleep 是否进行睡眠 bdaddr 蓝牙设备地址
-
hciconfig 的使用
hciconfig 用于配置蓝牙设备, hciX 是系统中安装的蓝牙设备的名称, 常用参数如下
-a 显示蓝牙设备信息 up 开启蓝牙设备 down 关闭蓝牙设备 reset 重置蓝牙设备 pscan 启用页面扫描,禁用查询扫描 -
btmon 的使用
btmon 是一个蓝牙监视器,会记录 Host 与 Controller 之间的 HCI 命令、事件和数据的交互
也有很多参数,不过一般直接输入
sudo btmon
执行监视 -
bluetoothctl 的使用
bluetoothctl 是输入命令操作蓝牙设备的工具,如搜索、配对、广播、连接等操作
终端输入
bluetoothctl
进入其环境,可以键入help
命令查看命令列表及其描述bluetoothctl 是一个新的操纵蓝牙设备的工具,相比于 hcitool、gatttool 等旧工具,更推荐使用 bluetoothctl
LINUX 下 UART HCI 例程
-
编译烧录到 esp32, UART 波特率可以在
Component config → Bluetooth → Bluetooth → Bluetooth controller → HCI UART(H4) Options
配置中进行修改默认是 921600 ,重启后 log 如下:
I (410) cpu_start: Starting scheduler on PRO CPU. I (0) cpu_start: Starting scheduler on APP CPU. I (443) CONTROLLER_UART_HCI: HCI UART1 Pin select: TX 5, RX 18, CTS 23, RTS 19 I (453) BTDM_INIT: BT controller compile version [5688ed5] I (453) system_api: Base MAC address is not set I (453) system_api: read default base MAC address from EFUSE I (463) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07 W (473) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
按照 log 中的引脚和 usb 转 ttl 串口工具的 RX、TX、RTS 和 CTS 引脚进行相连,串口工具连接在 linux 电脑上,使用 hciatttch 进行挂载
$ hciattach -s 921600 /dev/ttyUSB1 any 921600 flow nosleep Device setup complete # /dev/ttyUSB1 为串口工具串口 # 921600 为 menuconfig 中配置的波特率
使用 hciconfig 命令进行查看和启用设备
$ hciconfig hci0: Type: Primary Bus: UART BD Address: 24:0A:C4:F2:69:6E ACL MTU: 1021:9 SCO MTU: 255:4 UP RUNNING RX bytes:1113 acl:0 sco:0 events:61 errors:0 TX bytes:3247 acl:0 sco:0 commands:61 errors:0 $ sudo hciconfig hci0 up # hciconfig -a 会显示更详细的信息 # 如果 RX bytes 为 0,表示通路没打开,检查接线
再输入 bluetoothctl 进入 bluetoothctl 界面,同时可以在另一个 esp 设备运行 gatt_server_service_table 例程,来测试与 gatt server 的交互
$ bluetoothctl Agent registered [CHG] Controller 24:0A:C4:F2:69:6E Pairable: yes [bluetooth]# help 显示命令列表 [bluetooth]# scan on [NEW] Device 7C:DF:A1:BA:46:8D ESP_GATTS_DEMO [bluetooth]# scan off 打开和关闭扫描,可 menu scan 下进行配置扫描参数 [bluetooth]# conect 7C:DF:A1:BA:46:8D 连接 ESP_GATTS_DEMO 设备,连接成功会自动进行服务发现并 log 显示 [ESP_GATTS_DEMO]# menu gatt 进入 gatt 目录,若返回上一层使用 back [ESP_GATTS_DEMO]# list-attributes 列出对端被发现的属性条目 [ESP_GATTS_DEMO]# select-attribute 0000ff01-0000-1000-8000-00805f9b34fb 选择属性 [ESP_GATTS_DEMO:/service0028/char0029]# read 进行读请求操作 Attempting to read /org/bluez/hci0/dev_7C_DF_A1_BA_46_8D/service0028/char0029 [CHG] Attribute /org/bluez/hci0/dev_7C_DF_A1_BA_46_8D/service0028/char0029 Value: 11 22 33 44 ."3D 11 22 33 44 ."3D [ESP_GATTS_DEMO:/service0028/char0029]# write 0x09 进行写请求操作 【不知道怎样进行多个字节的写入】 Attempting to write /org/bluez/hci0/dev_7C_DF_A1_BA_46_8D/service0028/char0029 [ESP_GATTS_DEMO:/service0028/char0029]# notify on 使能 notify [CHG] Attribute /org/bluez/hci0/dev_7C_DF_A1_BA_46_8D/service0028/char0029 Notifying: yes Notify started [CHG] Attribute /org/bluez/hci0/dev_7C_DF_A1_BA_46_8D/service0028/char0029 Value: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e ...............
bluetoothctl 也可以配置 service 和设置 广播 name, 然后使用
advertise on
开启广播供 gatt client 设备连接和发现服务 (待探索) -
controller_hci_uart_esp32c3_and_esp32s3
与 controller_hci_uart_esp32 使用方法一样,操作对象是 esp32s3 和 esp32c3 ,相比于 esp32 ,蓝牙功能有所不同
- esp32s3 和 esp32c3 支持 BLE5.0 协议,兼容 esp32 支持的 BLE4.0 协议
- esp32s3 和 esp32c3 都没有 经典蓝牙控制器
-
初始化BT Controller后,发送简单 HCI 命令使 BT Controller 开启广播
static esp_vhci_host_callback_t vhci_host_cb = { controller_rcv_pkt_ready, // 用于通知 Controller 的上层可以发包给 Controller host_rcv_pkt // 接收 Controller 发送的 HCI packet 给 Controller 的上层 }; esp_vhci_host_register_callback(&vhci_host_cb); // 注册 vhci 接口的回调函数, Controller 返回数据将从回调中抛出 static int host_rcv_pkt(uint8_t *data, uint16_t len) { printf("host rcv pkt: "); for (uint16_t i = 0; i < len; i++) { printf("%02x", data[i]); } printf("\n"); return 0; } // 打印从 Controller 中发上来的 packet esp_vhci_host_send_packet(hci_cmd_buf, sz); // 发包给 Controller 的唯一接口 result = esp_vhci_host_check_send_available(); // 用于检查是否可以向 Controller 发送 packet,result 为 True 可以发包
controller_hci_uart_esp32 和 controller_hci_uart_esp32c3_and_esp32s3 使用 linux 串口调试工具选择 hex 输入以下指令,也可以像 controller_vhci_ble_adv 发出同样的广播, Host 与 Controller 的通讯通过一定格式的数据流(命令,事件和数据)进行通讯
# reset > 01030c00 # hci_cmd_send_ble_set_adv_param > 0106200f000100010000008584838281800700 # hci_cmd_send_ble_set_adv_data > 01082020120201060e094553502d424c452d48454c4c4f00000000000000000000000000 # hci_cmd_send_ble_adv_start > 010a200101
LINUX 下 USB HCI 例程
esp32s3 可以作为一个即插即用的 USB dongle 来使用,例程链接如下: usb-dongle
-
编译 demo
usb dongle 支持的功能组合如下,当打开 CDC 选项时,是不能组合 BT 功能的,而且这个是默认选项,因此编译前在 menuconfig 中关闭 CDC 功能
USB-ECM/RNDIS USB-BTH USB-CDC UART USB-DFU WEBUSB √ √ √ √ √ √ √ √ √ √ √ √ √ - Component config → TinyUSB Stack → Use TinyUSB Stack → Communication Device Class (CDC) 关闭 CDC 选项的使能
- Component config → TinyUSB Stack → Use TinyUSB Stack → Bluetooth Host Class (BTH) 打开 BTH 选项的使能
编译烧录后,插上 S3 开发板上的 USB 口到 linux 系统上,蓝牙功能会自动弹出,因为电脑能够根据描述符进行识别(tinyUSB 协议 ), 不需要使用 hciattach 进行挂载了
$ hciconfig hci0: Type: Primary Bus: USB BD Address: 7C:DF:A1:E0:0B:E6 ACL MTU: 251:12 SCO MTU: 0:0 UP RUNNING RX bytes:279 acl:0 sco:0 events:26 errors:0 TX bytes:159 acl:0 sco:0 commands:26 errors:0 $ sudo hciconfig hci0 up $ bluetoothctl Agent registered [CHG] Controller 7C:DF:A1:E0:0B:E6 Pairable: yes [bluetooth]# ...
-
使用 wireshark 抓取 USB-HCI 包
使用的是 usbmon 配合 wireshark 进行抓包, 抓包前使用以下命令无脑配置(如果不管事,自行搜索)
# 首次配置 sudo usermod -a -G wireshark xulongzhuang sudo mount -t debugfs none /sys/kernel/debug sudo addgroup usbmon sudo gpasswd -a $USER usbmon sudo vi /etc/udev/rules.d/99-usbmon.rules sudo modprobe usbmon sudo wireshark # 非首次启动配置 sudo modprobe usbmon sudo wireshark
其他传输接口
esp-hosted 工程支持蓝牙 Host 设备与蓝牙 Controller 设备之间的 sdio / spi / uart 的传输, 在传输方式上进行了灵活转换(蓝牙规范中是没有 SPI HCI 传输接口的定义)
使用 uart 传输时,从机选择配置 HCI UART(H4) 接口(Component config → Bluetooth → Bluetooth → Bluetooth controller → HCI mode )