Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
BlueZ D-Bus C,应用程序可扩展_C_Linux_Bluetooth Lowenergy_Bluez - Fatal编程技术网

BlueZ D-Bus C,应用程序可扩展

BlueZ D-Bus C,应用程序可扩展,c,linux,bluetooth-lowenergy,bluez,C,Linux,Bluetooth Lowenergy,Bluez,我正在尝试编写一个应用程序,搜索附近的蓝牙设备并与之通信。我的应用程序将用C编写,并打算在Linux下工作 在C中是否有通过D-Bus使用BlueZ的教程或示例? 此应用程序的目的是从BLE中的文件发送数据 您能帮我一下吗?您可以使用DBUS使用“StartDiscovery”适配器API查找附近的设备。使用下面的示例代码,您应该能够扫描附近的设备(BLE和Calssic)。但是,如果您只想扫描附近的BLE设备,可以使用“SetDiscoveryFilter”API将传输设置为“le”,并开始扫

我正在尝试编写一个应用程序,搜索附近的蓝牙设备并与之通信。我的应用程序将用C编写,并打算在Linux下工作

在C中是否有通过D-Bus使用BlueZ的教程或示例? 此应用程序的目的是从BLE中的文件发送数据


您能帮我一下吗?

您可以使用DBUS使用“StartDiscovery”适配器API查找附近的设备。使用下面的示例代码,您应该能够扫描附近的设备(BLE和Calssic)。但是,如果您只想扫描附近的BLE设备,可以使用“SetDiscoveryFilter”API将传输设置为“le”,并开始扫描BLE设备(查看下面的第二个示例)

/*
*bluez_适配器_scan.c-蓝牙设备的扫描
*-此示例在适配器通电后扫描新设备(如果有)
*出现在/org/hciX/dev_XX_YY_ZZ_AA_BB_CC中,使用“InterfaceAdded”进行监控
*打印设备的信号和所有属性
*-扫描将继续运行,直到任何设备消失,这将在180秒后发生
*如果设备未使用,则自动执行。
*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`
*/
#包括
#包括
GDBUS连接*con;
静态void bluez_属性_值(常量gchar*键,GVariant*值)
{
const gchar*type=g_variant_get_type_string(值);
g_打印(“\t%s:”,键);
开关(*类型){
案例“o”:
案例s:
g_print(“%s\n”,g_variant_get_string(value,NULL));
打破
案例“b”:
g_print(“%d\n”,g_variant_get_boolean(value));
打破
案例“u”:
g_print(“%d\n”,g_variant_get_uint32(value));
打破
案例“a”:
/*TODO只处理'as',不处理DICT数组*/
if(g_strcmp0(类型“as”))
打破
g_打印(“\n”);
常量gchar*uuid;
GVariantIterⅠ;
g_变体_iter_init(&i,值);
while(g_变体_iter_next(&i,“s”和uuid))
g\U打印(“\t\t%s\n”,uuid);
打破
违约:
g_print(“其他”);
打破
}
}
出现静态无效bluez_设备(GDBusConnection*sig,
const gchar*发送方名称,
常量gchar*对象路径,
常量gchar*接口,
常量gchar*信号名称,
GVariant*参数,
gpointer用户(U数据)
{
(无效)sig;
(无效)发件人姓名;
(void)对象路径;
(d)接口;
(无效)信号名称;
(作废)用户数据;
gVariantier*接口;
常量字符*对象;
常量gchar*接口名称;
GVariant*属性;
g_variant_get(参数,(&oa{sa{sv}})”、&object和接口);
而(g_变体_iter_下一个(接口){&s@a{sv}}“,&接口(名称和属性)){
if(g_strstr_len(g_ascii_strdown(接口名称,-1),-1,“设备”)){
g_print(“[%s]\n”,对象);
const gchar*属性名称;
GVariantIterⅠ;
G变量*属性值;
g_变体_iter_init(&i,属性);
while(g_variant_iter_next(&i,{&sv},&property_name,&prop_val))
bluez_属性值(属性名称、属性值);
g_变体_unref(prop_val);
}
g_变体_unref(属性);
}
返回;
}
#定义BT_地址_字符串_大小18
静态无效bluez_设备_消失(GDBusConnection*sig,
const gchar*发送方名称,
常量gchar*对象路径,
常量gchar*接口,
常量gchar*信号名称,
GVariant*参数,
gpointer用户(U数据)
{
(无效)sig;
(无效)发件人姓名;
(void)对象路径;
(d)接口;
(无效)信号名称;
gVariantier*接口;
常量字符*对象;
常量gchar*接口名称;
字符地址[BT_地址_字符串_大小]={'\0'};
g_variant_get(参数、(&oas)”、&object和接口);
while(g_变体_iter_next(接口,“s”和接口名称)){
if(g_strstr_len(g_ascii_strdown(接口名称,-1),-1,“设备”)){
int i;
char*tmp=g_strstr_len(对象,-1,“开发”)+4;
对于(i=0;*tmp!='\0';i++,tmp++){
如果(*tmp=='\'){
地址[i]=':';
继续;
}
地址[i]=*tmp;
}
g\U打印(“\n设备%s已删除,\n”,地址);
g_主循环退出((GMainLoop*)用户数据);
}
}
返回;
}
静态无效蓝色Z_信号_适配器_已更改(GDBUS连接*连接,
const gchar*发送方,
常量gchar*路径,
常量gchar*接口,
常量gchar*信号,
GVariant*params,
void*用户数据)
{
(无效)康涅狄格州;
(无效)发送方;
(无效)路径;
(d)接口;
(作废)用户数据;
GVariantIter*properties=NULL;
GVariantIter*未知=空;
const char*iface;
常量字符*键;
GVariant*value=NULL;
const gchar*signature=g_variant_get_type_string(参数);
if(g_strcmp0(签名,“(sa{sv}as)”)!=0){
g_print(“对%s的签名无效:%s!=%s”,信号,签名,“(sa{sv}as)”;
去做;
}
g_variant_get(params,(&sa{sv}as)”,&iface,&properties,&unknown);
while(g_variant_iter_next(properties,{&sv},&key,&value)){
如果(!g_strcmp0(键,“通电”)){
如果(!g_variant_是类型的(值,g_variant_type_BOOLEAN)){
g_print(“%s的参数类型无效:%s!=%s”,键,
g_变量_获取_类型_字符串(值),“b”);
去做;
}
/*
 * 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, "(&oa{sa{sv}})", &object, &interfaces);
    while(g_variant_iter_next(interfaces, "{&s@a{sv}}", &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, "(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)) {
        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;
}
/*
 * 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, "(&oa{sa{sv}})", &object, &interfaces);
    while(g_variant_iter_next(interfaces, "{&s@a{sv}}", &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, "(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)) {
        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;
}