蓝牙学习(2)USB Adapter

主要分析一下蓝牙USB Adapter使用USB接口传输HCI包的实现及过程。
这里写图片描述

参照上面的Bluetooth core system architecture图, 蓝牙USB Adapter作为Bluetooth controller以USB的物理形式连接到Linux host processor上,通过HCI protocol和Host通信。

bluetooth in Linux kernel

Linux kernel side主要包括:

  • Bluetooth Core: (net\bluetooth\*)
    • HCI (Host Controller Interface) device and connection manager, schedule
    • SCO (Synchronous Connection Oriented) audio links
    • L2CAP (Logical Link Control and Adaptation Protocol)
    • SMP (Security Manager Protocol) on LE (Low Energy) links
  • HCI Device drivers (Interface to the hardware)
    • USB (btusb)
    • UART (hciuart)
    • SDIO
  • RFCOMM (RFCOMM Protocol for serial communication) Module (creates /dev/rfcomm serial devices)
  • BNEP (Bluetooth Network Encapsulation Protocol) Module (creates /sys/class/net/bnep network interfaces)
  • CMTP (CAPI Message Transport Protocol) Module
  • HIDP (Human Interface Device Protocol) Module (creates /sys/class/input devices)

HCI device driver

HCI:Host Controller Interface

HCI提供了访问Controller的统一接口

Controller主要包含下面几种类型

  • BR/EDR Controller
  • BD/EDR/LE Controller
  • LE Controller
  • AMP Controller (Alternate MAC/PHY)

include/net/bluetooth/hci.h 中定义的HCI bus 接口类型包括:

/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB     1
#define HCI_PCCARD  2
#define HCI_UART    3
#define HCI_RS232   4
#define HCI_PCI     5
#define HCI_SDIO    6
#define HCI_SPI     7
#define HCI_I2C     8
#define HCI_SMD     9

btusb

bluetooth USB adapter是作为usb device挂载到USB总线上的。因此是通过usb_driver提供的机制去probe,而不是直接通过platform_driver.
这点和i2c, SPI 等设备驱动都是类似的。

static struct usb_driver btusb_driver = {
    .name       = "btusb",
    .probe      = btusb_probe,
    .disconnect = btusb_disconnect,
#ifdef CONFIG_PM
    .suspend    = btusb_suspend,
    .resume     = btusb_resume,
#endif
    .id_table   = btusb_table,
    .supports_autosuspend = 1,
    .disable_hub_initiated_lpm = 1,
};
probe

在probe函数中, hci device的operators函数指针被赋值

static int btusb_probe(struct usb_interface *intf,
               const struct usb_device_id *id)
{
    //...
    hdev->open   = btusb_open;
    hdev->close  = btusb_close;
    hdev->flush  = btusb_flush;
    hdev->send   = btusb_send_frame;
    hdev->notify = btusb_notify;
    //...
}

其中HCI Device数据结构定义, include/net/bluetooth/hci_core.h

struct hci_dev {
    struct list_head list;
    struct mutex    lock;
    char        name[8];
    unsigned long   flags;
    __u16       id;
    __u8        bus;
    __u8        dev_type;

    //...

    int (*open)(struct hci_dev *hdev);
    int (*close)(struct hci_dev *hdev);
    int (*flush)(struct hci_dev *hdev);
    int (*setup)(struct hci_dev *hdev);
    int (*shutdown)(struct hci_dev *hdev);
    int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
    void (*notify)(struct hci_dev *hdev, unsigned int evt);

    //...
    }  
接收发送数据

Bluetooth USB设备定义了不同的pipe用于不同类型的数据传输
- Control pipes are used to transport HCI commands.
- Interrupt pipes are responsible for carrying HCI events.
- Bulk pipes transfer asynchronous connectionless (ACL) Bluetooth data.
- Isochronous pipes carry SCO audio data.

static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
    struct urb *urb;
    BT_DBG("%s", hdev->name);
    switch (hci_skb_pkt_type(skb)) {
    case HCI_COMMAND_PKT:
        urb = alloc_ctrl_urb(hdev, skb);
        if (IS_ERR(urb))
            return PTR_ERR(urb);
        hdev->stat.cmd_tx++;
        return submit_or_queue_tx_urb(hdev, urb);
    case HCI_ACLDATA_PKT:
        urb = alloc_bulk_urb(hdev, skb);
        if (IS_ERR(urb))
            return PTR_ERR(urb);
        hdev->stat.acl_tx++;
        return submit_or_queue_tx_urb(hdev, urb);
    case HCI_SCODATA_PKT:
        if (hci_conn_num(hdev, SCO_LINK) < 1)
            return -ENODEV;
        urb = alloc_isoc_urb(hdev, skb);
        if (IS_ERR(urb))
            return PTR_ERR(urb);
        hdev->stat.sco_tx++;
        return submit_tx_urb(hdev, urb);
    }
    return -EILSEQ;
}

接收中断处理:
注册

btusb_open -->
btusb_submit_intr_urb-->
//initialize a interrupt urb
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
             btusb_intr_complete, hdev, data->intr_ep->bInterval);

usb_complete_t 回调函数btusb_intr_complete被注册

    if (btusb_recv_intr(data, urb->transfer_buffer,
                    urb->actual_length) < 0) {
            bt_dev_err(hdev, "corrupted event packet");
            hdev->stat.err_rx++;
        }

btusb_recv_intr函数中,数据被copy到skb. 内核中所有network相关的queue, buffer都用这个通用的结构体。

Reference

https://iotbreaks.com/base-knowledge-about-bluetooth/

http://www.embeddedlinux.org.cn/essentiallinuxdevicedrivers/final/ch16lev1sec1.html#ch16lev1sec1

https://wiki.linuxfoundation.org/networking/sk_buff

在Linux系统中,蓝牙适配器与DBus的交互是通过BlueZ协议栈实现的。BlueZ提供了一套基于DBus的接口,用于管理和控制蓝牙设备。DBus作为进程间通信(IPC)机制,允许应用程序与蓝牙适配器进行通信,从而实现设备发现、连接管理、服务发现等功能。 ### 蓝牙适配器的DBus接口 BlueZ为蓝牙适配器定义了`org.bluez.Adapter1`接口,该接口提供了多种方法来操作蓝牙设备。以下是一些常用的方法及其用途: - **StartDiscovery ()**:启动蓝牙设备扫描过程,用于发现附近的蓝牙设备。 - **StopDiscovery ()**:停止正在进行的蓝牙设备扫描。 - **GetProperties ()**:获取蓝牙适配器的当前属性,例如地址、名称、状态等。 - **SetProperty (in string, in variant)**:设置蓝牙适配器的某个属性,例如更改适配器的名称。 - **GetAllProperties ()**:获取蓝牙适配器的所有属性。 - **CreateDevice (in string, out object path)**:创建一个表示远程蓝牙设备的对象路径。 - **RemoveDevice (in object path)**:移除指定的蓝牙设备对象。 - **GetDevice (in object path, out object path)**:获取指定蓝牙设备的对象路径。 - **GetDevices (out array of object path)**:获取所有已知蓝牙设备的对象路径。 - **GetDeviceProperties (in object path, out dict of string variant)**:获取指定蓝牙设备的所有属性。 这些方法可以通过DBus命令行工具`dbus-send`或者编程方式调用,以实现对蓝牙适配器的控制。 ### 使用DBus命令行工具 可以使用`dbus-send`命令与蓝牙适配器进行交互。例如,获取蓝牙适配器的所有属性可以使用以下命令: ```bash dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0 org.freedesktop.DBus.Properties.GetAll string:org.bluez.Adapter1 ``` 其中,`/org/bluez/hci0`是蓝牙适配器的默认对象路径,`org.bluez.Adapter1`是要查询的接口名称。 ### 开发指南 对于开发者来说,BlueZ提供了一个基于DBus的API,可以通过编程方式访问蓝牙适配器。开发环境的搭建通常涉及安装BlueZ库及其依赖项,包括DBus库。以下是一个典型的配置命令示例: ```bash ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-experimental --enable-maintainer-mode --enable-pcm --enable-udev --enable-dbus --enable-bluez5 --enable-deprecated --enable-tools --enable-client --enable-hid --enable-avrcp --enable-a2dp --enable-socket --enable-cups --enable-ofono --enable-usb --enable-gstreamer --enable-gtk3 --enable-qt4 --enable-qt5 --enable-vala --enable-python --enable-java --enable-android --enable-ios --enable-macosx --enable-windows --enable-bluetoothd --enable-bluetoothctl --enable-btmon --enable-bccmd --enable-l2ping --enable-l2test --enable-dfutool --enable-hciattach --enable-hcidump --enable-hciemu --enable-hciconfig --enable-hcitool --enable-sdptool --enable-rfcomm --enable-ciptool --enable-bnep --enable-pan --enable-gn --enable-dund --enable-hidp --enable-avdtp --enable-avctp --enable-mcap --enable-health --enable-nfc --enable-swift --enable-tizen --enable-ivi --enable-automotive --enable-desktop --enable-mobile --enable-wearable --enable-accessibility --enable-testing --enable-debug --enable-coverage --enable-static --enable-shared --enable-strip --enable-install --enable-uninstall --enable-clean --enable-distclean --enable-maintainer-clean --enable-check --enable-parallel --enable-recursive --enable-no-undefined --enable-export-dynamic --enable-fast-install --enable-dependency-tracking --enable-silent-rules --enable-quiet-build --enable-color --enable-nls --enable-gettext --enable-intl --enable-libiconv --enable-libcharset --enable-threads --enable-thread-safe --enable-reentrancy --enable-multi-threaded --enable-posix --enable-win32 --enable-cygwin --enable-msys --enable-mingw32 --enable-macosx-universal --enable-macosx-deployment-target --enable-macosx-archs --enable-macosx-sdk --enable-macosx-sdkroot --enable-macosx-framework --enable-macosx-framework-name --enable-macosx-framework-version --enable-macosx-framework-install-name --enable-macosx-framework-resource-dir --enable-macosx-framework-executable-dir --enable-macosx-framework-library-dir --enable-macosx-framework-header-dir --enable-macosx-framework-man-dir --enable-macosx-framework-info-dir --enable-macosx-framework-doc-dir --enable-macosx-framework-example-dir --enable-macosx-framework-test-dir --enable-macosx-framework-benchmark-dir --enable-macosx-framework-data-dir --enable-macosx-framework-cache-dir --enable-macosx-framework-log-dir --enable-macosx-framework-temp-dir --enable-macosx-framework-var-dir --enable-macosx-framework-etc-dir --enable-macosx-framework-bin-dir --enable-macosx-framework-sbin-dir --enable-macosx-framework-libexec-dir --enable-macosx-framework-share-dir --enable-macosx-framework-include-dir --enable-macosx-framework-lib-dir --enable-macosx-framework-etc-dir --enable-macosx-framework-var-dir --enable-macosx-framework-cache-dir --enable-macosx-framework-log-dir --enable-macosx-framework-temp-dir --enable-macosx-framework-data-dir --enable-macosx-framework-doc-dir --enable-macosx-framework-info-dir --enable-macosx-framework-man-dir --enable-macosx-framework-example-dir --enable-macosx-framework-test-dir --enable-macosx-framework-benchmark-dir ``` 此命令配置BlueZ库以支持各种功能,包括DBus支持。开发者可以根据具体需求调整配置选项。 ### 示例代码 以下是一个简单的Python示例,展示如何使用`pydbus`库与蓝牙适配器进行交互: ```python from pydbus import SystemBus # 连接到系统总线 bus = SystemBus() # 获取BlueZ的蓝牙适配器对象 adapter = bus.get('org.bluez', '/org/bluez/hci0')['org.bluez.Adapter1'] # 获取蓝牙适配器的所有属性 properties = adapter.GetAll('org.bluez.Adapter1') print(properties) ``` 这段代码连接到系统总线,获取蓝牙适配器对象,并打印出适配器的所有属性。 ### 调试技巧 当遇到无法从`dbus-send`获取回复的问题时,可以尝试以下步骤进行调试: 1. **检查BlueZ服务状态**:确保BlueZ服务正在运行。可以使用`systemctl status bluetooth`命令检查服务状态。 2. **检查DBus服务**:确认DBus服务正常运行。可以使用`systemctl status dbus`命令检查服务状态。 3. **检查权限**:确保用户有权限访问蓝牙设备。可能需要将用户添加到`bluetooth`组。 4. **检查设备路径**:确认使用的设备路径是否正确。可以使用`hciconfig`命令查看蓝牙设备信息。 5. **使用`dbus-monitor`工具**:使用`dbus-monitor`工具监控DBus上的消息,帮助诊断问题。 通过这些步骤,可以有效地解决常见的DBus与蓝牙适配器交互问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值