我正在尝试在我们的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/