Bluetooth api in linux

Bluetooth Low-Energy on Linux API

I have a device with a few custom GATT services, and I would like to write a Linux program to interact with it. After some searching I found out that Linux is using BlueZ to handle the Bluetooth LE protocol. I’m using Ubuntu 15.10 with BlueZ 5.35, but I cannot figure out how use this BlueZ from a user-space program. I cannot find an API documentation anywhere, no tutorials, examples, nothing. Is it even possible to use this BlueZ stack to do anything other than just connecting to Bluetooth devices with default services? And if so, where is the documentation? (Preferably C/C++ API but at this point anything goes)

Yes it’s possible. But there is a learning curve. The bluez APIS are documented in the bluez tree. Those are all DBUS APIs. So to use them you first need to learn a bit about DBUS. There are different bindings to make use of DBUS. They include python, Glib and QT. There are others.

5 Answers 5

  • Have a look at attrib/gatttool.c in the bluez sources [1]. Gatttool is a command line utility for connecting to BTLE devices using the C «API». The GATT interface is not exposed in libbluetooth though.
  • A newer alternative to gatttool and thus another example to learn from is the btgatt-client, which you can find in tools/btgatt-client.c (to enable compilation configure bluez with —enable-experimental ).
  • Besides the C interface bluez integrated a DBUS interface. bluetoothctl is an example tool using the DBUS interface. The code of bluetoothctl can be found in client/ [2].
  • Another example program using the C interface of bluez is the Anki Drive SDK [3]. It packaged the bluez GATT C interface in its own library libbzle [4]. When using the C interface you have to connect a socket when establishing a BTLE connection. The gatttool does this via the GATT interface, which in turn uses glib iirc. But you can also do this using syscalls (socket, connect, . ) as explained e.g. here [5]. This document also explains:

Unfortunately, as of now there is no official API reference to refer to, so more curious readers are advised to download and examine the BlueZ source code.

Gilbert Brault also extracted the GATT interface from bluez [6] and links to a rudimentary doxygen documentation of the GATT interface [7] with the following disclaimer:

This is a work in progress with the intent of documenting all important functions and data structures

Also Szymon Janc gave a nice overview in his talk «Bluetooth on Modern Linux» at the Embedded Linux Conference 2016 [8]. Starting at 42:00 he talks about the unexposed C interface. But in general he seems to recommend the DBUS API (see «Tips» slide at 45:30). Some DBUS documentation can be found in doc/gatt-api.txt [9] and Python examples using the DBUS interface can be found in test/ .

I feel your pain. I needed to add user input from a custom BLE peripheral, a simple remote pushbutton, to an embedded program running under Linux (Stretch) on a Raspberry Pi. I was stunned by the needless complexity and Spartan (not a compliment) documentation of the BlueZ API. All the BlueZ “examples” are written from the perspective that Bluetooth is the center of the universe and the user wants to support every Bluetooth device ever invented. In my case I knew exactly the device, service, and GATT characteristics I needed to interact with, and I wanted a minimum overhead task that would do its thing in a low priority thread.

Читайте также:  Разница потоки процессы linux

It turns out a BLE central client is pretty straightforward using BlueZ, but it was an arduous road starting with the source for the BlueZ utility bluetoothctl in release 5.49. I accomplished my needs using only three unmodified source files from the BlueZ distribution and excerpts from an additional three source files. Since the BlueZ source is inextricably dependent on D-Bus and the Gnome GLib main loop, I grudgingly included them.

Following OlivierM’s generous lead, and in hopes that my embarrassingly massive investment in time saves someone else a month of their life, I have posted my example Bluetooth BLE client on GitHub: https://github.com/jjjsmit/BluetoothBLEClient

It would arguably be simpler and quicker to write a shell script on Linux to do what you need to do. The BlueZ commands are relatively simple and straightforward, and there are many tutorials and questions on how to use it.

Once you are more familiar with using the commands manually you can then write a minimal shell script so that this is automated for you.

Источник

Linux Bluetooth API Function Locations

I have Bluez installed and the daemon is up. I am trying to write a very simple program to make sure everything is working. I am referring to the documentation at index : bluez.git. My program is simple:

#include #include #include using namespace std; int main(int argc, char* argv[])
$: g++ read_write.cpp -o read_write -I/usr/include/bluetooth -lbluetooth read_write.cpp: In function ‘int main(int, char**)’: read_write.cpp:11:20: error: ‘StartDiscovery’ was not declared in this scope StartDiscovery(); 

Where are all the functions mentioned in the bluez docs actually at? Are there header files somewhere other than /usr/include/bluetooth that I need to reference?

According to GitHub | pauloborges | bluez, it looks like StartDiscovery is a d-bus message parameter, not a function call.

1 Answer 1

There are multiple ways to access functionality provided by BlueZ.

  1. Using D-Bus API (most common)
  2. Using HCI socket
  3. Using Management socket interface
    • All the API documentation in Bluez tree is about using D-Bus interfaces.
    • For using HCI socket you don’t need to run Bluetooth daemon in user space. You can directly communicate with Kernel using AF_BLUETOOTH socket and request for HCI inquiry (for scanning). But this is not recommended as Bluez developers moved to management socket interface.
    • Management sockets are similar to HCI sockets which is implemented in kernel space, but in more generic or one way to access the controller. In HCI socket any number of user space application can asynchronously control the Bluetooth controller/Adapter. You can find more information here: http://www.bluez.org/the-management-interface/
    • bluetoothd daemon internally uses management socket to achieve all the tasks mentioned in doc/API and exports the results/API in D-Bus, thus by hiding all the internals of management socket. Yes, still you can directly use management socket to communicate with Linux Kernel.
/* * 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 #include 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>)", &object, &interfaces); while(g_variant_iter_next(interfaces, ">", &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, "", &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] = ; 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, "(saas)") != 0) < g_print("Invalid signature for %s: %s != %s", signal, signature, "(saas)"); goto done; > g_variant_get(params, "(&saas)", &iface, &properties, &unknown); while(g_variant_iter_next(properties, "", &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; > 

This example is minimal to control the Bluetooth adapter property and start the scanning process using «StartDiscovery» method.

Читайте также:  Структурная схема ос linux

Источник

linux Bluetooth programming in c

I am trying to run a basic code of c in linux[ubuntu] to search bluetooth device, but i am facing some problem. By using command sudo apt-get install bluez , to install required blueZ library it is saying that bluez is already newest version. But error comes that not able to find bluetooth.h and other files in compiling C source code, with gcc -o simplescan simplescan.c -lbluetooth Is there a complete library package, or do I have to download these header files?. I am following this link

apt-get is not working, can i download this package from launchpad.net/ubuntu/lucid/+source/bluez/4.60-0ubuntu8

I am not able to use apt-get command, because i am not connected to internet, but can if i download these library from outside and use in my ubuntu PC through pendrive , is it possible 1) Glib library, 2) Dbus library,3) Bluez 4) Bluez Utilities

4 Answers 4

apt-get install libbluetooth-dev 

Maybe you didn’t include the essential header.

here’s an example of code to scan for bluetooth devices

#include #include #include #include #include #include #include int main(int argc, char **argv) < inquiry_info *ii = NULL; int max_rsp, num_rsp; int dev_id, sock, len, flags; int i; char addr[19] = < 0 >; char name[248] = < 0 >; dev_id = hci_get_route(NULL); sock = hci_open_dev( dev_id ); if (dev_id < 0 || sock < 0) < perror("opening socket"); exit(1); >len = 8; max_rsp = 255; flags = IREQ_CACHE_FLUSH; ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info)); num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags); if( num_rsp < 0 ) perror("hci_inquiry"); for (i = 0; i < num_rsp; i++) < ba2str(&(ii+i)->bdaddr, addr); memset(name, 0, sizeof(name)); if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0) strcpy(name, "[unknown]"); printf("%s %s\n", addr, name); >free( ii ); close( sock ); return 0; > 

to compile it on linux, just do

gcc -o simplescan simplescan.c -lbluetooth 

Original code can be found in here

Читайте также:  Netflow analyzer install linux

Источник

Оцените статью
Adblock
detector