3
votes

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)

2
Just put the code on here. Not everyone can access external websites and they may not exist for as long as StackOverflow does.Daniel Margosian

2 Answers

3
votes

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.
2
votes

You should not use the Bluez C functions at all. Instead use the newer GDBus functions. At https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/adapter-api.txt you can find out how to scan. Call StartDiscovery. The DBus devices will then be added as they are discovered. Listen to the interfaces-added signal to detect new devices. It's strange that you say no devices are detected, since it should work.

The ReadValue method should work. Are you connected to the device while you read?

Also check using hciconfig that the hci layer is UP. If nothing works, you can always run "sudo btmon" to get a capture of what's going on.