dbus 上 C 上的 Bluez 编程

Posted

技术标签:

【中文标题】dbus 上 C 上的 Bluez 编程【英文标题】:Bluez programming on C on dbus 【发布时间】:2019-02-24 08:39:35 【问题描述】:

我正在编写一个简单的代理应用程序。

我可以配对我的设备,但是当我尝试连接时(点击连接选项)它失败并显示以下 dbus 日志

我们将非常感谢您的帮助。

method call time=1537417845.746765 sender=:1.0 -> destination=:1.25 serial=2824 path=/org/bluez/AutoPinAgent; interface=org.bluez.Agent1; member=AuthorizeService
   object path "/org/bluez/hci0/dev_00_00_00_17_55_B8"
   string "00001108-0000-1000-8000-00805f9b34fb"
error time=1537417845.749340 sender=:1.25 -> destination=:1.0 error_name=org.freedesktop.DBus.Error.UnknownMethod reply_serial=2824
   string "No such interface 'org.bluez.Agent1' on object at path /org/bluez/AutoPinAgent"

【问题讨论】:

【参考方案1】:

如果没有代理的源代码以及您尝试连接的方式,真的很难判断。从日志中可以清楚地看出,当守护进程尝试连接 HSP 配置文件的 HS(headset) 角色时,它是通过调用您的代理的AuthorizeService 来请求授权。

从错误回复中,我了解到您没有向 Bluez 正确注册方法/接口。因此,您需要实现AuthorizeService 并在此配置文件尝试连接时授权服务。

以下是实现 Bluez 的 doc/agent-api.txt 的 Agent 示例。所以你需要根据你的需要在这个例子中实现AuthorizeService。本例只是模板代码,没有具体实现。

/*
 * gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/agent ./agent.c `pkg-config --libs glib-2.0 gio-2.0`
 */
#include <glib.h>
#include <gio/gio.h>
#include <stdio.h>

GMainLoop *loop;
GDBusConnection *con;
#define AGENT_PATH  "/org/bluez/AutoPinAgent"

static void bluez_agent_method_call(GDBusConnection *conn,
                    const gchar *sender,
                    const gchar *path,
                    const gchar *interface,
                    const gchar *method,
                    GVariant *params,
                    GDBusMethodInvocation *invocation,
                    void *userdata)

    int pass;
    int entered;
    char *opath;
    GVariant *p= g_dbus_method_invocation_get_parameters(invocation);

    g_print("Agent method call: %s.%s()\n", interface, method);
    if(!strcmp(method, "RequestPinCode")) 
        ;
    
    else if(!strcmp(method, "DisplayPinCode")) 
        ;
    
    else if(!strcmp(method, "RequestPasskey")) 
        g_print("Getting the Pin from user: ");
        fscanf(stdin, "%d", &pass);
        g_print("\n");
        g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", pass));
    
    else if(!strcmp(method, "DisplayPasskey")) 
        g_variant_get(params, "(ouq)", &opath, &pass, &entered);
        g_dbus_method_invocation_return_value(invocation, NULL);
    
    else if(!strcmp(method, "RequestConfirmation")) 
        g_variant_get(params, "(ou)", &opath, &pass);
        g_dbus_method_invocation_return_value(invocation, NULL);
    
    else if(!strcmp(method, "RequestAuthorization")) 
        ;
    
    else if(!strcmp(method, "AuthorizeService")) 
        ;
    
    else if(!strcmp(method, "Cancel")) 
        ;
    
    else
        g_print("We should not come here, unknown method\n");


static const GDBusInterfaceVTable agent_method_table = 
    .method_call = bluez_agent_method_call,
;

int bluez_register_agent(GDBusConnection *con)

    GError *error = NULL;
    guint id = 0;
    GDBusNodeInfo *info = NULL;

    static const gchar bluez_agent_introspection_xml[] =
        "<node name='/org/bluez/SampleAgent'>"
        "   <interface name='org.bluez.Agent1'>"
        "       <method name='Release'>"
        "       </method>"
        "       <method name='RequestPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='out' />"
        "       </method>"
        "       <method name='DisplayPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='in' />"
        "       </method>"
        "       <method name='RequestPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='out' />"
        "       </method>"
        "       <method name='DisplayPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "           <arg type='q' name='entered' direction='in' />"
        "       </method>"
        "       <method name='RequestConfirmation'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "       </method>"
        "       <method name='RequestAuthorization'>"
        "           <arg type='o' name='device' direction='in' />"
        "       </method>"
        "       <method name='AuthorizeService'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='uuid' direction='in' />"
        "       </method>"
        "       <method name='Cancel'>"
        "       </method>"
        "   </interface>"
        "</node>";

    info = g_dbus_node_info_new_for_xml(bluez_agent_introspection_xml, &error);
    if(error) 
        g_printerr("Unable to create node: %s\n", error->message);
        g_clear_error(&error);
        return 0;
    

    id = g_dbus_connection_register_object(con, 
            AGENT_PATH,
            info->interfaces[0],
            &agent_method_table,
            NULL, NULL, &error);
    g_dbus_node_info_unref(info);
    //g_dbus_connection_unregister_object(con, id);
    /* call register method in AgentManager1 interface */
    return id;


static int bluez_agent_call_method(const gchar *method, GVariant *param)

    GVariant *result;
    GError *error = NULL;

    result = g_dbus_connection_call_sync(con,
            "org.bluez",
            "/org/bluez",
            "org.bluez.AgentManager1",
            method,
            param,
            NULL,
            G_DBUS_CALL_FLAGS_NONE,
            -1,
            NULL,
            &error);
    if(error != NULL) 
        g_print("Register %s: %s\n", AGENT_PATH, error->message);
        return 1;
    

    g_variant_unref(result);
    return 0;


static int bluez_register_autopair_agent(const char *cap)

    int rc;

    rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, cap));
    if(rc)
        return 1;

    rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH));
    if(rc) 
        bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH));
        return 1;
    

    return 0;



static void cleanup_handler(int signo)

    if (signo == SIGINT) 
        g_print("received SIGINT\n");
        g_main_loop_quit(loop);
    


int main(int argc, char **argv)

    int id;
    int rc;

    if(argc < 2)
        return 1;

    if(signal(SIGINT, cleanup_handler) == SIG_ERR)
        g_print("can't catch SIGINT\n");

    con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
    if(con == NULL) 
        g_print("Not able to get connection to system bus\n");
        return 1;
    

    loop = g_main_loop_new(NULL, FALSE);

    id = bluez_register_agent(con);
    if(id == 0)
        goto fail;

    rc = bluez_register_autopair_agent(argv[1]);
    if(rc) 
        g_print("Not able to register default autopair agent\n");
        goto fail;
    

    g_main_loop_run(loop);

fail:
    g_dbus_connection_unregister_object(con, id);
    g_object_unref(con);
    return 0;

在编写我们自己的源代码之前,最好先从 bluetoothctl 基于 CLI 的配对和连接开始。

【讨论】:

以上是关于dbus 上 C 上的 Bluez 编程的主要内容,如果未能解决你的问题,请参考以下文章

BlueZ DBUS API - GATT 接口对 BLE 设备不可用

在 Bluez 中创建 dbus 接口

(Bluez) 如何获取蓝牙耳机按键输入?

C中的Dbus结构和方法调用

主动 BLE 扫描 (BlueZ) - DBus 问题

使用 QT/C++ 中的 DBUS 连接到新的 Bluez HDP 插件