c++bluetooth-lowenergybluezgdbus

Basic BLE client with D-Bus BlueZ


I'm working with (everybody's favourite) BlueZ 5.40 compiled and run with experimental features and I need to scan for LE devices, pair and connect to one and read/write a characteristic via the D-Bus API. I have studied sources of hcitool, gatttool and bluetootctl and made a basic application using GDBus. However, there are several problems with it.

  1. Scanning does not add /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX obj. path to org.bluez bus (checked using d-feet). This is not that surprising considered it's not D-Bus based, but I when I use StartDiscovery it does not detect my device at all. Neither does bluetoothctl.

After that I used gatttool and simple-agent as a workaround to create the object path and then connect using my program but I encountered another problem:

  1. When I try to read a characteristic I get a "The connection is closed (18)" error. I suspect this has nothing to do with the connection between bluetooth devices and it talks about D-Bus itself because when I try to set scanning filter for LE devices only, using SetDiscoveryFilter, I receive the same error.

Whenever I use only Connect and Disconnect functions everything seems to be working fine, but uses for applications like that are... limited. So my questions are:

  1. How to scan for LE devices using GDBus? If that is not possible, how to add a device manually or persuade bluetoothd to do it for me?

  2. How to read a characteristic properly?

The code is rather lengthy even after shortening, so I put it on pastebin: http://pastebin.com/YNLMF0qC.
Compile with g++ -std=c++11 $(pkg-config --cflags glib-2.0 gobject-2.0 gio-2.0) ./main.cpp $(pkg-config --libs glib-2.0 gobject-2.0 gio-2.0 bluez)


Solution

  • Finally got it right.
    1. Was solved recently by BlueZ 5.41. My device was "scannable" but not "discoverable". Meaning it broadcasted advertising packets, but because it did not permit connection without PIN to discover further services. In BlueZ 5.41 if you set any filter using SetDiscoveryFilter these devices too become visible during scanning. This is a recent (and not intuitive at all!) addition to https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/adapter-api.txt:

    When discovery filter is set, Device objects will be created as new devices with matching criteria are discovered regardless of they are connectable or discoverable which enables listening to non-connectable and non-discoverable devices.

    1. Was purely my mistake. As I said, I got the same error on ReadValue and SetDiscoveryFilter, but this error had nothing to do with DBus connection. It was caused by an incorrect GVariant argument. The correct form is "(a{sv})" not "({sv})". For example GVariant *args = g_variant_new_parsed("({'Transport': <%s>},)", "le"); for the SetDiscoveryFilter and GVariant *args = g_variant_new_parsed("({'offset': <%q>},)", offset); works fine.