Created
June 9, 2018 09:20
-
-
Save parthitce/efc12f131c8e85bb65a512ef9d5263ea to your computer and use it in GitHub Desktop.
StartDiscovery + RemoveDevice: Scan and remove the Bluetooth device
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* bluez_adapter_remove.c - Scan and remove 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 | |
* - 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_remove ./bluez_adapter_remove.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 int bluez_adapter_call_method(const char *method, GVariant *param) | |
{ | |
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, | |
param, | |
NULL, | |
G_DBUS_CALL_FLAGS_NONE, | |
-1, | |
NULL, | |
&error); | |
if(error != NULL) | |
return 1; | |
g_variant_unref(result); | |
return 0; | |
} | |
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; | |
} | |
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", NULL); | |
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", 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment