Linux 下 ESP32 蓝牙 HCI 例程的使用

HCI 简介

BLE 协议栈分为 Host 和 Controller 两大部分,通过 HCI (Host Controller Interface) 进行相互通讯,而 HCI 硬件传输接口又分为多种,包括 USB、UART 和 SDIO 等。 在 esp-idf 中 Host 分为 bluedroid 和 nimble, 相关的一些应用例程也在 bluedroidnimble 目录下,同时 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 例程

  • controller_hci_uart_esp32

    编译烧录到 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 都没有 经典蓝牙控制器
  • controller_vhci_ble_adv

    初始化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/RNDISUSB-BTHUSB-CDCUARTUSB-DFUWEBUSB
    • 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 )

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值