Linux 上 C blueZ 中的蓝牙配对

Posted

技术标签:

【中文标题】Linux 上 C blueZ 中的蓝牙配对【英文标题】:Bluetooth pairing in C blueZ on Linux 【发布时间】:2013-01-27 00:27:08 【问题描述】:

我找不到任何关于如何在使用 BlueZ 蓝牙库的 C 语言编写的程序中配对 Linux 上的蓝牙设备的参考资料。我已经设法进行 HCI 级别查询以获取设备以及他们的 RSSI 级别(在设备发现期间),但目前我坚持这一点。我看到了将 DBUS api 用于 blueZ-simple-agent 的建议 - 但有什么办法可以避免这种情况,而只使用 BlueZ 的一些 C 级方法?

【问题讨论】:

我在这里找到的一本非常酷的书在这方面帮助了我:people.csail.mit.edu/rudolph/Teaching/Articles/BTBook.pdf 它有 c 和 python 中的设置、配对等示例。我想尝试用它来启动蓝牙ipad 上的经典(spp)连接,但不认为内核有我需要的东西。 使用 bluetoothctl ,从 Bluez5 开始就可以使用,只需要打开代理就可以了 在这里回答了一个类似的问题:***.com/questions/29767053/bluez-programming它可能对你有帮助! 【参考方案1】:

您可以在这里下载最新版本的源代码:http://www.bluez.org/ 有“btmgmt”工具和可用于配对的 bluez-simple-agent。代码都在源代码中,还有一些文档(在 docs 文件夹中)。也许您可以根据需要使用其中一种工具的代码,或者它可以帮助您理解配对。

我想首先将 2 个设备与 bluez 蓝牙库配对,但我碰巧在 bluez-tools 的源代码中找到了有用的代码。 有文件“btmgmt.c”和其中包含的一些实现配对的文件。

对我来说不幸的是它不起作用,我不明白为什么。但也许你会取得更大的成功。以下是您可以测试它的方法。

如果您还没有,请在此处下载最新版本的源代码:http://www.bluez.org/ 解压并在 bluez 文件夹中打开一个终端。

然后在终端中运行以下命令:

./configure --prefix=/usr    \
        --sysconfdir=/etc    \
        --localstatedir=/var \
        --enable-tools       \
        --disable-test       \
        --disable-systemd

我不记得你需要安装的所有包,但你可以运行这个命令并检查它失败的原因,然后安装包并重新运行它直到它工作。如果您不知道需要安装哪个软件包,请询问 google。 之后:

make

现在您可以从终端切换到工具文件夹并输入 ./btmgmt 以查看如何使用它。 无论您身在何处,您都可以通过输入“btmgmt”来安装它。

sudo /usr/bin/install -c tools/btmgmt /usr/bin/btmgmt

您需要 sudo 权限才能使用它。

【讨论】:

【参考方案2】:

来自hcitool的验证码(原始源代码可以在http://git.kernel.org/cgit/bluetooth/bluez.git/tree/tools/hcitool.c看到)

/* Request authentication */

static void cmd_auth(int dev_id, int argc, char **argv)

        struct hci_conn_info_req *cr;
        bdaddr_t bdaddr;
        int opt, dd;

        for_each_opt(opt, auth_options, NULL) 
            switch (opt) 
            default:
                printf("%s", auth_help);
                return;
            
        
        helper_arg(1, 1, &argc, &argv, auth_help);

        str2ba(argv[0], &bdaddr);

        if (dev_id < 0) 
            dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
            if (dev_id < 0) 
                fprintf(stderr, "Not connected.\n");
                exit(1);
            
        

        dd = hci_open_dev(dev_id);
        if (dd < 0) 
            perror("HCI device open failed");
            exit(1);
        

        cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
        if (!cr) 
            perror("Can't allocate memory");
            exit(1);
        

        bacpy(&cr->bdaddr, &bdaddr);
        cr->type = ACL_LINK;
        if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) 
            perror("Get connection info failed");
            exit(1);
        

        if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) 
            perror("HCI authentication request failed");
            exit(1);
        

        free(cr);

        hci_close_dev(dd);

并设置 PIN

/* Activate encryption */

static void cmd_enc(int dev_id, int argc, char **argv)

    struct hci_conn_info_req *cr;
    bdaddr_t bdaddr;
    uint8_t encrypt;
    int opt, dd;

    for_each_opt(opt, enc_options, NULL) 
        switch (opt) 
        default:
            printf("%s", enc_help);
            return;
        
    
    helper_arg(1, 2, &argc, &argv, enc_help);

    str2ba(argv[0], &bdaddr);

    if (dev_id < 0) 
        dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
        if (dev_id < 0) 
            fprintf(stderr, "Not connected.\n");
            exit(1);
        
    

    dd = hci_open_dev(dev_id);
    if (dd < 0) 
        perror("HCI device open failed");
        exit(1);
    

    cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
    if (!cr) 
        perror("Can't allocate memory");
        exit(1);
    

    bacpy(&cr->bdaddr, &bdaddr);
    cr->type = ACL_LINK;
    if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) 
        perror("Get connection info failed");
        exit(1);
    

    encrypt = (argc > 1) ? atoi(argv[1]) : 1;

    if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) 
        perror("HCI set encryption request failed");
        exit(1);
    

    free(cr);

    hci_close_dev(dd);

【讨论】:

【参考方案3】:

此 dbus 命令可用于启动配对

 dbus-send --system --print-reply --dest=org.bluez /org/bluez/1301/hci0 org.bluez.Adapter.CreatePairedDevice string:"XX:XX:XX:XX:XX:XX" objpath:/org/bluez/agent_1317 string:"NoInputNoOutput"

这里1301是bluetoothd的进程id

/org/bluez/agent_1317是蓝牙配对代理。bluez/test中agent.c自带的bluezagent可以用于此目的。

【讨论】:

【参考方案4】:

我曾经在 C/C++ 中玩过 Bluez。据我了解,C/C++ 接口在 BlueZ 中对用户来说并不受欢迎,它确实更喜欢 python。

所以主要的想法是看一下 BlueZ 存储库,在目录 /tools 中实现了 C 中的一些必需功能。

另外,你可以看看这篇文章,它展示了从普通 C 中使用 BlueZ 的一些可能性:https://people.csail.mit.edu/albert/bluez-intro/c404.html

这是我想出的(基于 hcidump): https://github.com/IGR2014/Alsa-BlueZ-Example(灵感来自https://github.com/pauloborges/bluez,https://git.kernel.org/pub/scm/bluetooth/bluez.git)

连接函数可能实现的小例子:

// Connect to device
bool btCore::connect(const char* address) 

    std::cout << "Connecting to device\t" << address << " ..." << std::endl;
    std::cout << std::endl;

    uint16_t     handle;
    unsigned int ptype      = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;

    char         addr[19]   = 0;

    bdaddr_t     bdaddr;

    str2ba(address, &bdaddr);

    // Open local HCI device
    int sk      = hci_open_dev(dev_id);
    if (sk < 0) 

        std::cerr << "HCI open device:\t\t" << strerror(errno) << std::endl;
        return false;

    

    // Establish HCI connection with device
    if (hci_create_connection(sk, &bdaddr, htobs(ptype), 0, 0, &handle, 0) < 0) 

        std::cerr << "HCI create connection:\t" << strerror(errno) << std::endl;
        close(sk);
        return false;

     else 

        std::cout << "Connection:\t\tOK" << std::endl;

    

    // Authenticate HCI link (without pin)
    if (hci_authenticate_link(sk, handle, 0) < 0) 

        std::cerr << "HCI authenticate connection:\t" << strerror(errno) << std::endl;
        close(sk);
        return false;

     else 

        std::cout << "Authentication:\t\tOK" << std::endl;

    

    // Encrypt HCI link
    if (hci_encrypt_link(sk, handle, 1, 0) < 0) 

        std::cerr << "HCI encrypt connection:\t" << strerror(errno) << std::endl;
        close(sk);
                return false;

     else 

        std::cout << "Encryption:\t\tOK" << std::endl;

    

    close(sk);

    return true;


接下来您要做的是发现服务 (https://www.bluetooth.com/specifications/assigned-numbers/service-discovery)

还有我的老问题可以引导你回答:C++ Bluetooth headphones under Linux over BlueZ

请注意:所有 API(如果我们可以将这些内部函数命名为“API”)不保证与其他版本的 BlueZ 相同。至少,对此类行为没有任何保证。

【讨论】:

以上是关于Linux 上 C blueZ 中的蓝牙配对的主要内容,如果未能解决你的问题,请参考以下文章

Linux over BlueZ下的C++蓝牙耳机

Linux下基于Bluez

c语言中的linux蓝牙编程

Qt 蓝牙与 Linux

如何在 C++ 中使用 Bluez5 DBUS API 来配对和连接新设备?

[BlueZ] 2使用bluetoothctl搜索连接配对读写使能notify蓝牙低功耗设备