BlueZ D-Bus C , 应用 BLE
Posted
技术标签:
【中文标题】BlueZ D-Bus C , 应用 BLE【英文标题】:BlueZ D-Bus C , application BLE 【发布时间】:2018-11-13 12:09:33 【问题描述】:我正在尝试编写一个搜索附近的蓝牙设备并与它们通信的应用程序。我的应用程序将用 C 语言编写,并打算在 Linux 下运行。
是否有任何教程或示例通过 C 中的 D-Bus 使用 BlueZ? 此应用程序的目的是从 BLE 中的文件发送数据。
你能帮帮我吗?
【问题讨论】:
这很可能是一个风滚草,因为一开始就缺乏数据和努力,或者更有可能因为“太宽泛”而被关闭。请阅读How to create a Minimal, Complete, and Verifiable example 并访问Help Center 以了解如何提出可回答的问题。祝你好运! 你可以在这里查看:github.com/S3ler/SimpleBluetoothLowEnergySocket 我目前正在为蓝牙经典开发一些示例,您可以在这里找到源代码:gist.github.com/parthitce 和信息最少的博客linumiz.com/category/blog 【参考方案1】:您可以使用 DBUS 的“StartDiscovery”适配器 API 找到附近的设备。使用下面的示例代码,您应该能够扫描附近的设备(BLE 和 Calssic)。但如果您只想扫描附近的 BLE 设备,您可以使用“SetDiscoveryFilter”API 将传输设置为“le”并开始扫描 BLE 设备(请查看下面的第二个示例)。
/*
* bluez_adapter_scan.c - Scan for bluetooth devices
* - This example scans for new devices after powering the adapter, if any devices
* appeared in /org/hciX/dev_XX_YY_ZZ_AA_BB_CC, it is monitered using "InterfaceAdded"
* signal and all the properties of the device is printed
* - Scanning continues to run until any device is disappered, this happens after 180 seconds
* automatically if the device is not used.
* gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/bluez_adapter_scan ./bluez_adapter_scan.c `pkg-config --libs glib-2.0 gio-2.0`
*/
#include <glib.h>
#include <gio/gio.h>
GDBusConnection *con;
static void bluez_property_value(const gchar *key, GVariant *value)
const gchar *type = g_variant_get_type_string(value);
g_print("\t%s : ", key);
switch(*type)
case 'o':
case 's':
g_print("%s\n", g_variant_get_string(value, NULL));
break;
case 'b':
g_print("%d\n", g_variant_get_boolean(value));
break;
case 'u':
g_print("%d\n", g_variant_get_uint32(value));
break;
case 'a':
/* TODO Handling only 'as', but not array of dicts */
if(g_strcmp0(type, "as"))
break;
g_print("\n");
const gchar *uuid;
GVariantIter i;
g_variant_iter_init(&i, value);
while(g_variant_iter_next(&i, "s", &uuid))
g_print("\t\t%s\n", uuid);
break;
default:
g_print("Other\n");
break;
static void bluez_device_appeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
(void)user_data;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
GVariant *properties;
g_variant_get(parameters, "(&oasasv)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "&s@asv", &interface_name, &properties))
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device"))
g_print("[ %s ]\n", object);
const gchar *property_name;
GVariantIter i;
GVariant *prop_val;
g_variant_iter_init(&i, properties);
while(g_variant_iter_next(&i, "&sv", &property_name, &prop_val))
bluez_property_value(property_name, prop_val);
g_variant_unref(prop_val);
g_variant_unref(properties);
return;
#define BT_ADDRESS_STRING_SIZE 18
static void bluez_device_disappeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
char address[BT_ADDRESS_STRING_SIZE] = '\0';
g_variant_get(parameters, "(&oas)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "s", &interface_name))
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device"))
int i;
char *tmp = g_strstr_len(object, -1, "dev_") + 4;
for(i = 0; *tmp != '\0'; i++, tmp++)
if(*tmp == '_')
address[i] = ':';
continue;
address[i] = *tmp;
g_print("\nDevice %s removed\n", address);
g_main_loop_quit((GMainLoop *)user_data);
return;
static void bluez_signal_adapter_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
(void)conn;
(void)sender;
(void)path;
(void)interface;
(void)userdata;
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(g_strcmp0(signature, "(sasvas)") != 0)
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sasvas)");
goto done;
g_variant_get(params, "(&sasvas)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "&sv", &key, &value))
if(!g_strcmp0(key, "Powered"))
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;
g_print("Adapter is Powered \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
if(!g_strcmp0(key, "Discovering"))
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;
g_print("Adapter scan \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
static int bluez_adapter_call_method(const char *method)
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
/* TODO Find the adapter path runtime */
"/org/bluez/hci0",
"org.bluez.Adapter1",
method,
NULL,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;
g_variant_unref(result);
return 0;
static int bluez_adapter_set_property(const char *prop, GVariant *value)
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez/hci0",
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new("(ssv)", "org.bluez.Adapter1", prop, value),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;
g_variant_unref(result);
return 0;
int main(void)
GMainLoop *loop;
int rc;
guint prop_changed;
guint iface_added;
guint iface_removed;
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);
prop_changed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Adapter1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_adapter_changed,
NULL,
NULL);
iface_added = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_appeared,
loop,
NULL);
iface_removed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_disappeared,
loop,
NULL);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", TRUE));
if(rc)
g_print("Not able to enable the adapter\n");
goto fail;
rc = bluez_adapter_call_method("StartDiscovery");
if(rc)
g_print("Not able to scan for new devices\n");
goto fail;
g_main_loop_run(loop);
rc = bluez_adapter_call_method("StopDiscovery");
if(rc)
g_print("Not able to stop scanning\n");
g_usleep(100);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", FALSE));
if(rc)
g_print("Not able to disable the adapter\n");
fail:
g_dbus_connection_signal_unsubscribe(con, prop_changed);
g_dbus_connection_signal_unsubscribe(con, iface_added);
g_dbus_connection_signal_unsubscribe(con, iface_removed);
g_object_unref(con);
return 0;
使用 SetDiscoveryFilter 仅扫描 BLE 设备的示例。
/*
* bluez_adapter_filter.c - Set discovery filter, Scan for bluetooth devices
* - Control three discovery filter parameter from command line,
* - auto/bredr/le
* - RSSI (0:very close range to -100:far away)
* - UUID (only one as of now)
* Example run: ./bin/bluez_adapter_filter bredr 100 00001105-0000-1000-8000-00805f9b34fb
* - This example scans for new devices after powering the adapter, if any devices
* appeared in /org/hciX/dev_XX_YY_ZZ_AA_BB_CC, it is monitered using "InterfaceAdded"
* signal and all the properties of the device is printed
* - Device will be removed immediately after it appears in InterfacesAdded signal, so
* InterfacesRemoved will be called which quits the main loop
* gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/bluez_adapter_filter ./bluez_adapter_filter.c `pkg-config --libs glib-2.0 gio-2.0`
*/
#include <glib.h>
#include <gio/gio.h>
GDBusConnection *con;
static void bluez_property_value(const gchar *key, GVariant *value)
const gchar *type = g_variant_get_type_string(value);
g_print("\t%s : ", key);
switch(*type)
case 'o':
case 's':
g_print("%s\n", g_variant_get_string(value, NULL));
break;
case 'b':
g_print("%d\n", g_variant_get_boolean(value));
break;
case 'u':
g_print("%d\n", g_variant_get_uint32(value));
break;
case 'a':
/* TODO Handling only 'as', but not array of dicts */
if(g_strcmp0(type, "as"))
break;
g_print("\n");
const gchar *uuid;
GVariantIter i;
g_variant_iter_init(&i, value);
while(g_variant_iter_next(&i, "s", &uuid))
g_print("\t\t%s\n", uuid);
break;
default:
g_print("Other\n");
break;
typedef void (*method_cb_t)(GObject *, GAsyncResult *, gpointer);
static int bluez_adapter_call_method(const char *method, GVariant *param, method_cb_t method_cb)
GError *error = NULL;
g_dbus_connection_call(con,
"org.bluez",
/* TODO Find the adapter path runtime */
"/org/bluez/hci0",
"org.bluez.Adapter1",
method,
param,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
method_cb,
&error);
if(error != NULL)
return 1;
return 0;
static void bluez_get_discovery_filter_cb(GObject *con,
GAsyncResult *res,
gpointer data)
(void)data;
GVariant *result = NULL;
result = g_dbus_connection_call_finish((GDBusConnection *)con, res, NULL);
if(result == NULL)
g_print("Unable to get result for GetDiscoveryFilter\n");
if(result)
result = g_variant_get_child_value(result, 0);
bluez_property_value("GetDiscoveryFilter", result);
g_variant_unref(result);
static void bluez_device_appeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
(void)user_data;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
GVariant *properties;
//int rc;
g_variant_get(parameters, "(&oasasv)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "&s@asv", &interface_name, &properties))
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device"))
g_print("[ %s ]\n", object);
const gchar *property_name;
GVariantIter i;
GVariant *prop_val;
g_variant_iter_init(&i, properties);
while(g_variant_iter_next(&i, "&sv", &property_name, &prop_val))
bluez_property_value(property_name, prop_val);
g_variant_unref(prop_val);
g_variant_unref(properties);
/*
rc = bluez_adapter_call_method("RemoveDevice", g_variant_new("(o)", object));
if(rc)
g_print("Not able to remove %s\n", object);
*/
return;
#define BT_ADDRESS_STRING_SIZE 18
static void bluez_device_disappeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
char address[BT_ADDRESS_STRING_SIZE] = '\0';
g_variant_get(parameters, "(&oas)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "s", &interface_name))
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device"))
int i;
char *tmp = g_strstr_len(object, -1, "dev_") + 4;
for(i = 0; *tmp != '\0'; i++, tmp++)
if(*tmp == '_')
address[i] = ':';
continue;
address[i] = *tmp;
g_print("\nDevice %s removed\n", address);
g_main_loop_quit((GMainLoop *)user_data);
return;
static void bluez_signal_adapter_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
(void)conn;
(void)sender;
(void)path;
(void)interface;
(void)userdata;
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, "(sasvas)") != 0)
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sasvas)");
goto done;
g_variant_get(params, "(&sasvas)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "&sv", &key, &value))
if(!g_strcmp0(key, "Powered"))
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;
g_print("Adapter is Powered \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
if(!g_strcmp0(key, "Discovering"))
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;
g_print("Adapter scan \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
static int bluez_adapter_set_property(const char *prop, GVariant *value)
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez/hci0",
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new("(ssv)", "org.bluez.Adapter1", prop, value),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;
g_variant_unref(result);
return 0;
static int bluez_set_discovery_filter(char **argv)
int rc;
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_VARDICT);
g_variant_builder_add(b, "sv", "Transport", g_variant_new_string(argv[1]));
g_variant_builder_add(b, "sv", "RSSI", g_variant_new_int16(-g_ascii_strtod(argv[2], NULL)));
g_variant_builder_add(b, "sv", "DuplicateData", g_variant_new_boolean(FALSE));
GVariantBuilder *u = g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY);
g_variant_builder_add(u, "s", argv[3]);
g_variant_builder_add(b, "sv", "UUIDs", g_variant_builder_end(u));
GVariant *device_dict = g_variant_builder_end(b);
g_variant_builder_unref(u);
g_variant_builder_unref(b);
rc = bluez_adapter_call_method("SetDiscoveryFilter", g_variant_new_tuple(&device_dict, 1), NULL);
if(rc)
g_print("Not able to set discovery filter\n");
return 1;
rc = bluez_adapter_call_method("GetDiscoveryFilters",
NULL,
bluez_get_discovery_filter_cb);
if(rc)
g_print("Not able to get discovery filter\n");
return 1;
return 0;
int main(int argc, char **argv)
GMainLoop *loop;
int rc;
guint prop_changed;
guint iface_added;
guint iface_removed;
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);
prop_changed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Adapter1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_adapter_changed,
NULL,
NULL);
iface_added = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_appeared,
loop,
NULL);
iface_removed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_disappeared,
loop,
NULL);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", TRUE));
if(rc)
g_print("Not able to enable the adapter\n");
goto fail;
if(argc > 3)
rc = bluez_set_discovery_filter(argv);
if(rc)
goto fail;
rc = bluez_adapter_call_method("StartDiscovery", NULL, NULL);
if(rc)
g_print("Not able to scan for new devices\n");
goto fail;
g_main_loop_run(loop);
if(argc > 3)
rc = bluez_adapter_call_method("SetDiscoveryFilter", NULL, NULL);
if(rc)
g_print("Not able to remove discovery filter\n");
rc = bluez_adapter_call_method("StopDiscovery", NULL, NULL);
if(rc)
g_print("Not able to stop scanning\n");
g_usleep(100);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", FALSE));
if(rc)
g_print("Not able to disable the adapter\n");
fail:
g_dbus_connection_signal_unsubscribe(con, prop_changed);
g_dbus_connection_signal_unsubscribe(con, iface_added);
g_dbus_connection_signal_unsubscribe(con, iface_removed);
g_object_unref(con);
return 0;
您还可以找到有关 StartDiscovery 示例 here 和 SetDiscoveryFilter here 的一些解释。
【讨论】:
以上是关于BlueZ D-Bus C , 应用 BLE的主要内容,如果未能解决你的问题,请参考以下文章
Python+D-Bus+BlueZ 5:无法读取对象的属性?