我正在尝试在我们的Android应用使用rfcomm套接字连接到的计算机上更新蓝牙代码。到目前为止,我们对蓝牙使用--compat选项和一些SDP功能来注册我们的蓝牙服务。现在,我想在Bluez 5中使用DBus API来减少它的易碎性,并可能在首次配对后使自动连接和自动信任工作。

我可以在org.bluez.ProfileManager1上使用RegisterProfile方法注册配置文件,然后使用bluetoothctl在contoller上看到我的自定义uuid,而android应用也可以看到它。然后,我需要一些回调以在设备连接时触发,以使我可以写入套接字。我可以在org.bluez.Device1上注册PropertiesChanged信号,这确实会在连接和断开连接时触发,但没有给我一个套接字。我尝试在org.bluez.Profile1的回调中注册一个对象,但这不会触发。我不太确定应该如何处理UUID,因为我们将使用具有众所周知的UUID的SPP,但是我也想避免噪音和与其他使用该设备的设备混淆,它只能与我们的应用程序对话。

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;
}


回调注册成功完成,没有错误,其输出为:

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


所以我不明白为什么我的函数connection_callback永远不会触发。
我感谢所有输入,我对DBus和蓝牙都不熟悉

最佳答案

我的解决方案是将bluez从5.37升级到5.50。
我还遵循How do I register a profile with bluez using dbus/gio?上的解决方案
升级后也没有尝试过。尽管没有升级,但仅此一项没有帮助

关于c - 如何使用Bluez Profile1 DBus API注册连接回调,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57511364/

10-11 15:45