用于蓝牙的 GLib client/server
GLib for bluetooth client/server
我正在尝试学习如何使用 C 语言中的蓝牙和 GLib(通过 D-Bus 连接)连接服务器和客户端。
我已经使用此代码成功注册了我的服务及其自己的 UUID:
注册函数:
int register_profile(GDBusProxy *proxy,
gchar *service_path,
gchar *service_name,
gint service_channel,
gchar *service_uuid)
{
GVariant *profile;
GVariantBuilder profile_builder;
GError *error = NULL;
g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osa{sv})"));
if (!g_variant_is_object_path(service_path))
{
return ERR_CUSTOM_PATH_INVALID;
}
g_variant_builder_add(&profile_builder, "o", service_path);
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(service_channel));
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(service_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(service_name));
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 RESULT_OK;
}
return -1;
}
接收连接事件的代码:
static void signal_device_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
{
g_print("Signal Device changed");
}
我用这个初始化代码:
int register_service(char *service_path,
char *service_name,
int service_channel,
char *service_uuid)
{
GDBusProxy *proxy;
GDBusConnection *conn, *pconn;
GError *error = NULL;
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,
"org.bluez",
"/org/bluez",
"org.bluez.ProfileManager1",
NULL,
&error);
g_assert_no_error(error);
error = NULL;
int result = register_profile(proxy, service_path, service_name, service_channel, service_uuid);
if (result != RESULT_OK)
{
return result;
}
pconn = g_dbus_proxy_get_connection(proxy);
guint sub_id = g_dbus_connection_signal_subscribe(pconn,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Device1",
G_DBUS_SIGNAL_FLAGS_NONE,
signal_device_changed,
NULL,
NULL);
g_print("Registration successful with subscription id [%d]. Press [ENTER] to exit.", sub_id);
char c;
result = scanf("%c", &c);
g_dbus_connection_signal_unsubscribe(pconn, sub_id);
g_object_unref(pconn);
g_object_unref(proxy);
g_object_unref(conn);
return RESULT_OK;
}
我使用 python 客户端应用程序(我用 python 服务器测试过,它在我用来测试的设备上运行)连接到上述服务器:
- 可以找到自定义UUID
- 似乎 连接到它(它说它可以找到 UUID 服务并创建到它的连接)
- 但我没有看到我的
signal_device_changed
函数被调用
我尝试使用 conn
而不是代理连接,结果相同。
我是不是忘记了什么?
我使用的信息来自:
根据@ukBaz 的建议,我需要进入主循环。我修改了服务注册中的代码如下:
// Beginning is same
serverUserData *userData = malloc(sizeof(serverUserData));
userData->loop = g_main_loop_new(NULL, FALSE);
guint sub_id = g_dbus_connection_signal_subscribe(pconn,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Device1",
G_DBUS_SIGNAL_FLAGS_NONE,
signal_device_changed,
userData,
NULL);
if (sub_id > 0)
{
g_print("Registration successful with subscription id [%d].\n", sub_id);
}
g_main_loop_run(userData->loop);
g_dbus_connection_signal_unsubscribe(pconn, sub_id);
if (pconn != NULL)
g_object_unref(pconn);
if (proxy != NULL)
g_object_unref(proxy);
if (conn != NULL)
g_object_unref(conn);
当设备断开连接时,我退出了主循环。
接下来我需要弄清楚如何创建 RFCOMM 套接字连接并监听它。但如果我遇到问题,我会在另一个问题中做。
我正在尝试学习如何使用 C 语言中的蓝牙和 GLib(通过 D-Bus 连接)连接服务器和客户端。 我已经使用此代码成功注册了我的服务及其自己的 UUID:
注册函数:
int register_profile(GDBusProxy *proxy,
gchar *service_path,
gchar *service_name,
gint service_channel,
gchar *service_uuid)
{
GVariant *profile;
GVariantBuilder profile_builder;
GError *error = NULL;
g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osa{sv})"));
if (!g_variant_is_object_path(service_path))
{
return ERR_CUSTOM_PATH_INVALID;
}
g_variant_builder_add(&profile_builder, "o", service_path);
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(service_channel));
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(service_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(service_name));
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 RESULT_OK;
}
return -1;
}
接收连接事件的代码:
static void signal_device_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
{
g_print("Signal Device changed");
}
我用这个初始化代码:
int register_service(char *service_path,
char *service_name,
int service_channel,
char *service_uuid)
{
GDBusProxy *proxy;
GDBusConnection *conn, *pconn;
GError *error = NULL;
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,
"org.bluez",
"/org/bluez",
"org.bluez.ProfileManager1",
NULL,
&error);
g_assert_no_error(error);
error = NULL;
int result = register_profile(proxy, service_path, service_name, service_channel, service_uuid);
if (result != RESULT_OK)
{
return result;
}
pconn = g_dbus_proxy_get_connection(proxy);
guint sub_id = g_dbus_connection_signal_subscribe(pconn,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Device1",
G_DBUS_SIGNAL_FLAGS_NONE,
signal_device_changed,
NULL,
NULL);
g_print("Registration successful with subscription id [%d]. Press [ENTER] to exit.", sub_id);
char c;
result = scanf("%c", &c);
g_dbus_connection_signal_unsubscribe(pconn, sub_id);
g_object_unref(pconn);
g_object_unref(proxy);
g_object_unref(conn);
return RESULT_OK;
}
我使用 python 客户端应用程序(我用 python 服务器测试过,它在我用来测试的设备上运行)连接到上述服务器:
- 可以找到自定义UUID
- 似乎 连接到它(它说它可以找到 UUID 服务并创建到它的连接)
- 但我没有看到我的
signal_device_changed
函数被调用
我尝试使用 conn
而不是代理连接,结果相同。
我是不是忘记了什么?
我使用的信息来自:
根据@ukBaz 的建议,我需要进入主循环。我修改了服务注册中的代码如下:
// Beginning is same
serverUserData *userData = malloc(sizeof(serverUserData));
userData->loop = g_main_loop_new(NULL, FALSE);
guint sub_id = g_dbus_connection_signal_subscribe(pconn,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Device1",
G_DBUS_SIGNAL_FLAGS_NONE,
signal_device_changed,
userData,
NULL);
if (sub_id > 0)
{
g_print("Registration successful with subscription id [%d].\n", sub_id);
}
g_main_loop_run(userData->loop);
g_dbus_connection_signal_unsubscribe(pconn, sub_id);
if (pconn != NULL)
g_object_unref(pconn);
if (proxy != NULL)
g_object_unref(proxy);
if (conn != NULL)
g_object_unref(conn);
当设备断开连接时,我退出了主循环。
接下来我需要弄清楚如何创建 RFCOMM 套接字连接并监听它。但如果我遇到问题,我会在另一个问题中做。