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.
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:
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:
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?
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)
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.
"(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.