简体   繁体   English

如何使用Bluez Profile1 DBus API注册连接回调

[英]How to register connection callbacks with Bluez Profile1 DBus API

I'm trying to update our bluetooth code on a computer that our android app connects to using rfcomm socket. 我正在尝试在我们的Android应用程序使用rfcomm套接字连接到的计算机上更新蓝牙代码。 Until now we have used the --compat option for bluetoothd and some SDP functions to register our bluetooth service. 到目前为止,我们对蓝牙使用--compat选项和一些SDP函数来注册我们的蓝牙服务。 Now I want to use the DBus API in Bluez 5 to make it less flaky and possibly make auto-connect and auto-trust work after first pairing. 现在,我想在Bluez 5中使用DBus API来减轻它的不稳定,并可能在首次配对后使自动连接和自动信任工作。

I can register a profile using the RegisterProfile method at org.bluez.ProfileManager1, then I see my custom uuid at the contoller using bluetoothctl, and the android app see it too. 我可以在org.bluez.ProfileManager1上使用RegisterProfile方法注册配置文件,然后使用bluetoothctl在控制器上看到我的自定义uuid,而android应用程序也看到了。 Then I need some callback to trigger when the device is connected to have a socket I can write to. 然后,我需要一些回调以在设备连接时触发,以使我可以写入套接字。 I can register for the PropertiesChanged signal at org.bluez.Device1, and this does trigger at both connect and disconnect, but it doesn't give me a socket. 我可以在org.bluez.Device1上注册PropertiesChanged信号,这确实会在连接和断开连接时触发,但没有给我一个套接字。 I try to register an object with callbacks at org.bluez.Profile1, but this just won't trigger. 我尝试在org.bluez.Profile1的回调中注册一个对象,但这不会触发。 I'm not quite sure how UUIDs should be handled either since we will use SPP which has a well known UUID, but I would also like to avoid noise and confusion with other devices that uses this, it should only talk to our app. 我不太确定应该如何处理UUID,因为我们将使用具有众所周知的UUID的SPP,但是我也想避免噪音和与其他使用此UUID的设备混淆,它只能与我们的应用程序通信。

static const gchar btp_introspection_xml[] =
    "<node>"
    "  <interface name='org.bluez.Profile1'>"
    "    <method name='Release' />"
    "    <method name='NewConnection'>"
    "      <arg type='o' name='device' direction='in' />"
    "      <arg type='h' name='fd' direction='in' />"
    "      <arg type='a{sv}' name='fd_properties' direction='in' />"
    "    </method>"
    "    <method name='RequestDisconnection'>"
    "      <arg type='o' name='device' direction='in' />"
    "    </method>"
    "  </interface>"
    "</node>";


int register_profile(GDBusProxy *proxy)
{
    GVariant *profile;
    GVariantBuilder profile_builder;
    GError *error = NULL;

    printf("register_profile called!\n");

    g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osa{sv})"));

    if (g_variant_is_object_path("/org/bluez/customprofile")) {
        printf("object path is good!\n");
    }

    g_variant_builder_add (&profile_builder, "o",
            "/org/bluez/customprofile");

    g_variant_builder_add (&profile_builder, "s", SERIAL_PORT_PROFILE_UUID);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("a{sv}"));


    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));   
    g_variant_builder_add (&profile_builder, "s", "Channel");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_uint16(22));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Service");
    g_variant_builder_add (&profile_builder, "v",
            g_variant_new_string(CUSTOM_UUID));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Name");
    g_variant_builder_add (&profile_builder, "v",
            g_variant_new_string("Custom Serial Port"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Role");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_string("server"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthentication");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthorization");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "AutoConnect");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(TRUE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_close(&profile_builder);
    profile = g_variant_builder_end(&profile_builder);

    GVariant * ret = g_dbus_proxy_call_sync (proxy,
                "RegisterProfile",
                profile,
                G_DBUS_CALL_FLAGS_NONE,
                -1,
                NULL,
                &error);
    g_assert_no_error(error);
    if(ret != NULL && error==NULL){
        return 0;
    } else {
        return 1;
    }
}


static void connection_callback(GDBusConnection *conn, const char *sender,
        const char *path, const char *interface, const char *method, GVariant *params,
        GDBusMethodInvocation *invocation, void *userdata) {

    g_print("Called: %s.%s()", interface, method);
    (void)conn;
    (void)sender;
    (void)path;
    (void)params;

    if (strcmp(method, "NewConnection") == 0)
        g_print("connected");
    else if (strcmp(method, "RequestDisconnection") == 0)
        g_print("disconnected");
    else if (strcmp(method, "Release") == 0)
        g_print("released?");

}

static void bluez_signal_device_changed(GDBusConnection *conn,
                    const gchar *sender,
                    const gchar *path,
                    const gchar *interface,
                    const gchar *signal,
                    GVariant *params,
                    gpointer userdata)
{
    (void)conn;
    (void)sender;
    (void)path;
    (void)interface;

    GVariantIter *properties = NULL;
    GVariantIter *unknown = NULL;
    const char *iface;
    const char *key;
    GVariant *value = NULL;
    const gchar *signature = g_variant_get_type_string(params);

    if(strcmp(signature, "(sa{sv}as)") != 0) {
        g_print("Invalid signature for %s: %s != %s", signal, signature, "(sa{sv}as)");
        goto done;
    }

    g_variant_get(params, "(&sa{sv}as)", &iface, &properties, &unknown);
    while(g_variant_iter_next(properties, "{&sv}", &key, &value)) {
    g_print("key: %s | value: %s\n",key,value);
        if(!g_strcmp0(key, "Connected")) {
            if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
                g_print("Invalid argument type for %s: %s != %s", key,
                        g_variant_get_type_string(value), "b");
                goto done;
            }
        gboolean status = g_variant_get_boolean(value);
            g_print("Device is \"%s\"\n", status ? "Connected" : "Disconnected");
        if (status) {
        //handle connection here instead?
        } else {
        g_print("stopping writer");
        stop_bt_writer();
        destroy_json_handler();
        }

        }
    }


done:
    if(properties != NULL)
        g_variant_iter_free(properties);
    if(value != NULL)
        g_variant_unref(value);
}


void init_server()
{
    GDBusProxy *proxy;
    GDBusConnection *conn;
    GError *error = NULL;
    OrgBluezProfile1 *interface;

    GMainLoop *loop = g_main_loop_new (NULL, FALSE);

    conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
    g_assert_no_error (error);

    proxy = g_dbus_proxy_new_sync (conn,
                G_DBUS_PROXY_FLAGS_NONE,
                NULL,/* GDBusInterfaceInfo */
                "org.bluez",/* name */
                "/org/bluez",/* object path */
                "org.bluez.ProfileManager1",/* interface */
                NULL,/* GCancellable */
                &error);
    g_assert_no_error (error);
    error=NULL;
    if (register_profile (proxy)) {
        printf("profile register failed\n");
        return;
    }
    printf("SPP profile registered");

    //register device property callback (connect/disconnect)
    guint sub_id = g_dbus_connection_signal_subscribe(conn,
                    "org.bluez",
                    "org.freedesktop.DBus.Properties",
                    "PropertiesChanged",
                    NULL,
                    "org.bluez.Device1",
                    G_DBUS_SIGNAL_FLAGS_NONE,
                    bluez_signal_device_changed,
                    NULL,
                    NULL);

    static GDBusInterfaceVTable vtable = {
        .method_call = connection_callback,
    };

    GDBusNodeInfo *introspection = g_dbus_node_info_new_for_xml(btp_introspection_xml, &error);
    GDBusInterfaceInfo *interface_info = g_dbus_node_info_lookup_interface(introspection, "org.bluez.Profile1");
    g_assert_no_error (error);
    error=NULL;
    guint regid = g_dbus_connection_register_object(conn,
                    "/org/bluez/customprofile",
                    interface_info,
                    &vtable,
                    NULL,
                    NULL,
                    &error);
    g_assert_no_error (error);
    printf("connection callback registered, id: %d;",regid);
    g_main_loop_run (loop);

    g_object_unref (proxy);
    g_object_unref (conn);

    return;
}

The callback registration completes without error, the output from this is: 回调注册成功完成,没有错误,其输出为:

register_profile called!
object path is good!
SPP profile registered
connection callback registered, id: 1;

So I dont understand why my function connection_callback never triggers. 所以我不明白为什么我的函数connection_callback永远不会触发。 I appreciate all input, I am not experienced in neither DBus nor bluetooth 我感谢所有输入,我对DBus和蓝牙都不熟悉

My solution was to upgrade bluez from 5.37 to 5.50. 我的解决方案是将bluez从5.37升级到5.50。 I also followed the solution on How do I register a profile with bluez using dbus/gio? 我还遵循了如何使用dbus / gio在bluez中注册配置文件的解决方案 and have not tried without this after upgrading. 升级后也没有尝试过。 That alone did not help without upgrading though 尽管没有升级,但仅此一项没有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM