Bluetooth: ConnectDevice without scanning

After discovering the nearby Bluetooth devices either using StartDiscovery without filter or with SetDiscovertFilter, next big step is to connect with the device and access the functionalities provided by the device. The connection process involves two steps,

  1. Pairing – Authenticating and trusting the end bluetooth device
  2. Connect itself

Here connection can be initiated either by the Bluetooth device or by the Bluetooth adapter itself on behalf of application. The Authentication mechanism involves accepting the device/adapter using PIN/confirmation key. We are not going in details about the Secure Simple Pairing (SSP) of Bluetooth here as bluetoothd hides all the details already. Bluez5 uses Agent style implementation of authentication in favor to the external application. To understand in details, lets assume the following use case,

  • User wants to connect to the Car Infotainment System (IVI) using bluetooth and initiates the connection from the mobile device. In this case, IVI head unit displays the PIN/confirmation code based on its Agent configurations. Then the user enters the same PIN or confirm yes/no from the mobile device. In this use case,
    • IVI wants to show up the confirmation/PIN in its own wizard or pop (e.g GTK)
    • Mobile device wants to pop up confirmation/Input field in its wizard

In favor of such implementations, Bluez5 provide Agent style API’s i.e Bluetooth Application can register it’s capability (yes/no confirmation or PIN entry) and also it’s own wizard implementation with the bluetoothd. Whenever there is a new connection from a device, bluetoothd automatically takes care to callback the registered API (where wizard or user application is implemented).

From the flow diagram, you can see,

  • UI application registers its capability with method callbacks with bluetoothd
  • StartDiscovery for scanning new devices
  • Pair with the device
    • bluetoothd callsback the API in UI for PIN/confirmation about the authentication
    • Based on the response, bluetoothd decides to proceed or not for pairing
  • Followed by Connect call to the Device1 interface (we will explore this interface in detail in next few blogs)

To get started with connection and for the completeness of the API’s coverage in adapter-api.txt, we will first explore the “ConnectDevice” API introduced in Bluez 5.49. As of this blogging date, this API is marked experimental for testing (mostly stable). To explore the below example on ConnectDevice, one must run the bluetoothd service/daemon in experimental mode by passing “-E” as argument.

Code:

ConnectDevice: This API is introduced in favor of answering following questions,

When this API is useful?

  • When you already have the MAC address of end bluetooth Device to connect with, then you don’t need to scan for the device (with or without filter) and connect it.
  • StartDiscovery + Pair + Connect => ConnectDevice

How you will have MAC address before scanning?

  • When you have other communication (wired or wireless) medium to exchange the MAC address
  • For example, NFC OOB can be used to exchange the MAC address
  • Testing Bluetooth with same device (MAC address known)

In such cases ConnectDevice can be directly called with “MAC address” of the bluetooth device to connect with as argument (as string, not as object path). In addition to the MAC address, Address Type (optional argument) can also be specified as argument to this method. For simplicity and better understanding we are going stick to only MAC address.

Before using the ConnectDevice method, we need to register our own agent which needs to be called for pairing process. Again for simplicity and for better understanding we are registering “NoInputOutput” without any method callbacks. This means, our bluetooth adapters Agen capability is similar to the one in Bluetooth headset, where user doesn’t need to care about pairing authentication. We will explore in detail about Agen API and all the methods in next blog before getting into device-api.

This example program takes the MAC address (XX:YY:ZZ:AA:BB:CC format) as argument which is directly fed into ConnectDevice method. Also note that this example uses Linux signal handler for SIGINT (Control + c from console) to gracefully handle the program exit.

BeagleBone UART peripheral boot

BeagleBone Black serial peripheral boot: 

BBB supports many peripheral boot options which can be choosen by the SYSBOOT button projected out near p8 header.

Button pressed the sequence is spi0 | mmc0 | usb0 | uart0
Button released the sequence is mmc1 | mmc0 | uart0 | usb0

so we have uart0 in both the sequence. We go for the sequence when button is pressed.
Here ROM code accepts the xmodem protocol for receiving the binary file so in Linux we have sx command for that.

$ sx -vvv <bin file> < <device file> > <device file>

Bluetooth: SetDiscoveryFilter for filtered scanning

In continuation to our previous blog on bluetooth scanning and remove device after scanning, we will explore on discovery filters. Filters are typically used to narrow down our search. By default “StartDiscovery” will scan for all the nearby bluetooth devices. But in many situations user/developer already knows the desired category of devices.

Few examples are,

  • Developer wants to search only for Apple devices
  • User only wants to search for Bluetooth low energy devices
  • Search only for the devices which are very closely located

To control or narrow down our search for devices during “StartDiscovery”, bluetoothd provides “SetDiscoveryFilter” D-Bus API. We will explore in details about the “filter” options which can be used.

Code:

Here we are extending our previous start discovery example by adding new functions for handling discovery filters. More specifically the function “bluez_set_discovery_filter” is introduced to handle the discovery filter.

Extracted from,

dbus-send –system –print-reply –type=method_call –dest=’org.bluez’ ‘/org/bluez/hci0’ org.freedesktop.DBus.Introspectable.Introspect

<methodname="SetDiscoveryFilter">
<argname="properties" type="a{sv}" direction="in"/>
</method>

<methodname="GetDiscoveryFilters">
<argname="filters" type="as" direction="out"/>
</method>

Before using the “SetDiscoveryFilter” method, we will first examine the method parameters in details. As we can see above it takes the signature type “a{sv}” as input argument and there is no output response. The counter part API GetDiscoveryFilters can be used to get the currently active filters.

There are 5 filters which we can use.

  • UUIDs:
    • as: we can specify the array of UUID stings to filter the supported services. In bluetoothd, all the functionalities are exported or referenced by unique UUID. Services can either be built in to bluetoothd as profiles or implemented as external profiles.
    • array of UUIDs filter can be used to find devices which supports the specified list of UUIDs. All the other devices will not be listed and will not be populated in /org/bluez/hciX/dev_ path.
  • RSSI:
    • Received Signal Strength Indication refers to the signal strength of the device, which is signed integer i.e. 0 to -100. Where 0 indicates the device is very close and -100 shows the devices is far away from the controller
    • We can specify this value to filter the devices with only in defined range. For example, value “-50” means, the scanning will pop all the devices between 0 to -50 in signal strength
  • Pathloss: Attenuation of the Bluetooth signal in the space
  • Transport: Possible values are “auto, bredr, le
    • bredr: Scan only Bluetooth classic devices
    • le: Scan only for bluetooth low energy devices
    • auto: Both le and bredr if the controller supports. This is the default value when no explicit filter is set for transport.
  • DuplicateData: Specific to low every Bluetooth devices advertisement values. When enabled, signal will be emitted everytime when the device is discovered.

In our example, we are using only “Transport, RSSI and UUID” to filter the discovery. All three values _must_ be specified in the same order as argument.

So far in our previous examples of GetManagedObjects, InterfacesAdded, InterfacesRemoved and PropertiesChanged we have handled various DBUS signatures and decoded the values using GDBUS and GVariant API’s. But in this example we need to formulate/create “a{sv}” to send as argument to SetDiscoveryFilter.

In this example we are using GVariant builder API’s to build the GVariant of our interest. You can refer GVariant manual for more details on how to build your variants. We will explore more in details about GVariants building and parsing in our future blog on DBUS specification and it’s type system. The device with specified filter will be populated under /org/bluez/hciX/dev_ and this program will exit after removal of any device (either automatically after 180 seconds of device idleness or explicit removal using “RemoveDevice” or bluetoothcrl remove).

Bluetooth: RemoveDevice to remove the device

In our previous example we have seen method to scan for nearby devices. In this blog we will extend the same example to remove the device explicitly.

Code:

In our previous example while exploring “StartDiscovery” method, we have seen “InterfacesRemoved” signal which will be emitted when any object path or interfaces inside a object path is removed.

We have also seen, bluetoothd will automatically remove the devices after 180 seconds which are populated during scanning process if the devices are not used. This does not apply for the devices which are paired or connected. Apart from this automatic removal, one can remove the device using “RemoveDevice” method. This method can be used any devices, i.e devices which are

  • appeared during scanning but not used
  • paired but not connected
  • paired and connected

RemoveDevice takes an argument to the object path i.e /org/bluez/hciX/dev_XX_YY_ZZ_AA_BB_CC. In the above extended example, we are removing the device immediately after it’s apperance during the scanning process. So while handling “InterfacesAdded” we are printing the device information and removing it.

As we are also watching on “InterfacesRemoved” signal, device removal triggers this signal callback handler and which it turn prints the device MAC address which is removed and finally quits the main loop.

This means, we exiting our program once we find at least one device in range. If no devices are found, this program remains in indefinite scanning mode.

Bluetooth: Adapter scan for new devices using “StartDiscovery”

So far we have seen ways to get Adapter properties, set the properties and also to list the devices using GetManagedObjects. To get started with real Bluetooth operation in action we need to understand the general use case and methods to achieve it. First thing in communication using Bluetooth is for,

  • Sharing some data (file, music, voice calls) between the Adapter and device
  • To achieve this, one must need to connect with the device. For this,
    • We need to scan for the Bluetooth device nearby
    • Pair with the device
    • Connect with the device

To get this action going we will get started with scanning for the nearby Bluetooth devices. This can be done using DBUS method “StartDiscovery“, as the name suggests, it starts the discovery session for the nearby devices.

Code:

This sample does the following things in order,

  • Subscribes for “PropertiesChanged” signal
    • We already saw the details about PropertiesChanged signal handling in our “set property” example. Here we repeat the same signal subscription to print the current power state of the Adapter.
    • We also filtering our signal for the property “Discoveringhere. This property is readonly and it will be automatically set by Bluetoothd when discovery session is started and stopped respectively.
  • Subscribes for “InterfacesAdded” signal
    • This signal is emitted for two notification events,
      1. New object path added:
        • For example, /org/bluez/hciX will appear automatically when you power on Bluetooth adapter (powering on the Adapter which is already powered on doesn’t create new object path and no signal will be generated). This internally means, bluetoothd is creating this object path when a new controlled is added and emit this signal to notify the changes.
        • More importantly, when we start scanning for new devices using “StartDiscovery” method, bluetoothd creates a new object path for every new devices which are discovered. For example, /org/bluez/hci0/dev_XX_YY_ZZ_AA_BB_CC will be created when a new device with MAC address XX:YY:ZZ:AA:BB:CC is found during scanning process by hci0 adapter.
      2. When an object path gains a new interface: This happens when a new interface is dynamically added by the DBUS service during runtime under the object path. We will explore this use case when understanding media interface for audio playback.
    • Signature pattern: “(oa{sa{sv}})“. This is similar to the one which we discussed already about GetManagedObject in out get property example. The difference is GetManagedObject’s signature is “a{oa{sa{sv}}}“, which returns the array of all the object path under a particular service. Whereas in this signature “(oa{sa{sv}})“, during InterfacesAdded we will get only the particular object path which is added or gains new interface. So,
      • o – object path which is added or gained the interface(s)
      • a{s – array of interfaces which are newly added or appeared after new object path created
      • a{sv} – array of properties. Note: We still didn’t explore about the DICT entries in a signature. I will move the scope explaining all the signature in details to future blogs about DBUS to avoid more confusion here.
  • Subscribes for “InterfacesRemoved” signal
    • This signal is emitted for two notification events
      1. Object path is removed:
        • For example, If Bluetooth adapter is removed (assuming USB Bluetooth dongle here) or powered off, then /org/bluez/hciX will be disappeared and this signal will be generated to notify.
        • More importantly, either a device removed explicitly using “RemoveDevice” method (which we see in out next blog with sample source) or the device path is removed automatically. bluetoothd automatically removes the device from the cache after 180 seconds of no action (like pairing or connection) i.e idleness of the device.  This is the cleanup action against all the devices which are not used after 180 seconds. If the device is paired or connected, bluetoothd will leave it untouched.
      2. When an interface is removed from an object path: This happens when a new interface is dynamically removed by the DBUS service during runtime under the object path. We will explore this use case when understanding media interface for audio playback.
    • Signature pattern: “(oas)“. This pattern is very simple to understand and process.
      • o – Object path which is removed or interfaces under this object path is removed
      • as – array of interface names which are removed. Note that there is no properties and values informed under this signal. This is because, properties changes are informed using “PropertiesChanged” signal. DBUS client application developer should be careful in releasing all the memory or references to the properties, interfaces and object path (including proxies if created) which is removed using this signal.
  • Power on the Adapter: See more details about this in Set property example.
  • Starts the discovery session
    • bluez_adapter_call_method function is implemented in such a way to handle both start and stop discovery method call under Adapter1 interface. There is no response or reply for this method (i.e. void return type). This is because the devices are appeared on the fly during scanning and new devices needs to be handled using InterfacesAdded signal.
  • Wait for at least one device removal action
    • bluez_device_disappeared for InterfacesRemoved is written in such a way to exit the mail loop of the program when at least one device is removed from the object path. This can happen
      • If any device is cleaned up after 180 seconds by bluetoothd OR
      • If the device is removed using “RemoveDevice” method call. One can achieve this using bluetoothctl utility to avoid waiting for 180 seconds of execution time.
  • Stop the discovery session: Stops the discovery session
  • Power off the Adapter: See more details about this in Set property example.

In this example, we are printing all the information about the device when it is appeared and printing only the MAC address when the device is disappeared (as we are not storing any device information when it is appeared).

Bluetooth: List devices using GDBUS

In this blog we will jump back to use GetManagedObjects method to find the list of Bluetooth devices which are currently present in all the Adapters. This sample in continuation to set property blog will help us understand more about Bluetooth devices and Adapters.

Code:

In this example above we are using GetManagedObjects method in org.freedesktop.DBus.ObjectManager interface to get all the objects for a specific interface. Unlike Properties interface, ObjectManager interface is specific to a service.

To recall,

  • org.freedesktop.DBus.Properties – available in all the object paths to manage properties of the interfaces.
  • org.freedesktop.DBus.ObjectManager – available in all the services. For example, org.bluez, org.ofono

GetManagedObjects method in this interface is specifically used to get all the objects (objects paths, interfaces, properties, property values) for a service. We are using it for “org.bluez” here.

More importantly, the output format for GetManagedObjects is “(a{oa{sa{sv}}})“. This signature is already explained here, in which we are filtering only the object paths with Device1 interface (Bluetooth devices). We will examine more details about the interface in our next blog for Bluetooth scanning.

After filtering the Device1 interface, all the properties of the device is printed. You can find the list of possible properties for a device here in Bluez tree.

dbus-send:

We can get the same output using dbus-send using the following command,

dbus-send –system –print-reply –type=method_call –dest=’org.bluez’ ‘/’ org.freedesktop.DBus.ObjectManager.GetManagedObjects

bluetooth: Set Adapter Powered property and watch signal using GDBUS

In this blog we will continue our understanding toward BlueZ to set the property in Adapter1 interface in continuation to our Get Property sample. As DBUS based applications can be accessed by any number of clients, modification a property needs to be informed to all the clients. In DBUS this can be done using signals.

So in this example we will also watch for the modification of a property which we change in our sample.

Code:

Signal Subscription:

To get the notification/signal before we change the property we must subscribe for the signal which we want with a callback function. To brief, from DBUS specification we have,

In our case, we are be subscribing to PropertiesChanged signal using g_dbus_connection_signal_subscribe. In which we need to specify the following,

sender – Service of interest, org.bluez in our case

interface name – org.freedesktop.DBus.Properties. Bluez5 follows latest DBUS specification, i.e

org.freedesktop.DBus.Properties – Is the common interface which needs to be used by any objects paths for handling the properties. For example, /org/bluez/hci0 is the object paths for HCI0 bluetooth adapter which can have following interfaces,

  • org.bluez.Adapter1
  • org.bluez.GattManager1
  • org.bluez.LEAdvertisingManager1
  • org.bluez.Media1
  • org.bluez.NetworkServer1
  • org.freedesktop.DBus.Properties

org.freedesktop.DBus.Properties is designed in a such a way to handle properties of all the interfaces of an object path. So “org.freedesktop.DBus.Properties” will be present in all the object paths. To access the property for an interface, one must specify the interface name and property name.

org.freedesktop.DBus.Properties provides three generic methods,

  • Get  (interface name, property name) – Input: {ss} Output: {v}
  • GetAll (interface name) – Input: {s} Output: a{sv}
  • Set (interface name, property name, property value) – Input: {ssv} Output: None

Refer DBUS specification for more details.

member – “PropertiesChanged” i.e the signal of interest

We have also filters and flags along with object path to limit/narrow down the signal for our client application (will be covered in future blog).

Set property:

To set the property, as stated above we are using “Set” method in “org.freedesktop.DBus.Properties” interface i.e {ssv} as argument,

s – interface name : org.bluez.Adapter1

s – property name : Powered

v – value as variant

We are toggling the power state i.e switching the Bluetooth Adapter “on” and “off”.

Jumping back to signal handling:

Looking back in signal handler, the output format is “(sa{sv}as)“. Here,

s – Interface name in which the property is changed

a{sv} – Array of properties which are changed and it’s new value.

as – Invalidated property (which we will examine in our future blog in detail), not needed for this example.

By parsing the property array we will be able to identify the property which are changed, here we are straight comparing against the property name and printing it.

For the ease of understanding, the program’s main loop is exited after getting the power off notification in signal handling.

dbus-send:

Same way as stated in our previous blogs, setting the property and watching for the change in also possible using dbus-send. To set the Powered property, use the following

dbus-send –system –print-reply –dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.Set string:”org.bluez.Adapter1″ string:”Powered” variant:boolean:true

Signal can be monitored in dbus-send using,

dbus-monitor –system “type=signal,path=’path=/org/bluez/hci0′,interface=’org.freedesktop.DBus.Properties'”

bluetooth: Get Adapter (controller) properties using GDBUS

In this blog we extent our previous example list HCI controller using GDBUS method to get the properties of the Adapter. We will examine the Adapter properties both by using “GetManagedObject” and also using “GetAll” method in org.freedesktop.DBus.Properties interface.

Code:

In our previous example we have used GetManagedObject and filtered the output only to view Adapter related information (Adapter MAC address and Name). Here we further extended the iteration to view the property of all the interfaces. The same information can also obtained from “GetAll” method in properties interface.

Most important things to note in this sample is the signature which is used to parse the output. For GetManagedObjects we have “a{oa{sa{sv}}}” and GetAll we have {sv}. To understand the format used by DBUS for marshalling and serializing the data one must understand the DBUS type systems. Explaining the complete type system and it’s organization in DBUS is beyond the scope of this blog, but will be covered in dedicated future blog for DBUS specification.

For now, a{oa{sa{sv}}} means,

a{0 – array of object paths (i.e. like int a[10] – array of 10 integers). For example, /org/bluez, /org/bluez/hci0, /org/bluez/hci1, /org/bluez/hci1/dev_XX_YY_ZZ_AA_BB_CC

a{s – array of interfaces. For example, org.bluez.ProfileManager1, org.bluez.Adapter1. Note that our previous curly braces is not closed yet, which means “array of object paths, where each object path may have array of interfaces”. Something like “array of arrays”

a{s – array of properties. Which means, “for each interface, we have array of properties”.

v – variant value. Variant as literally meaning, it can be string, integer, boolean, array of string or even array of arrays. So this details will be part of the software, in our case it’s Bluez. To have specific examples, Adapter Name is a string, Powered is boolean and UUID’s is array of strings.

For GetAll we have “{sv}“, which is again the same representation as in GetManagedObjects for “array of properties name and it’s values in variant”. One can always use “g_variant_get_type_string” to get the exact signature of the data before processing the data.

The same output of GetAll can be observed using dbus-send command. Try the following command after adjusting the adapter path.

dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/org/bluez/hci0' org.freedesktop.DBus.Properties.GetAll string:"org.bluez.Adapter1"

bluetooth: List available controllers using DBUS

This blog is the continuation of list controllers using HCI interface, to cover the same use case using DBUS interface provided by Bluez. We will be using the “GetManagedObjects” methid to get the list of Bluetooth controllers.

Using GDBUS:

Using GDBUS Proxy:

If Bluetooth service is not running, you can start it using,

systemctl start bluetooth

As described in the in Bluez Blog D-Bus ObjectManager section, one should use “GetManagedObjects” method provided by the “org.freedesktop.DBus.ObjectManager” interface to get list of available Bluetooth controllers by filtering the interface name againt “Adapter1“. Here in our examples, after obtaining the object paths, we are using the “org.freedesktop.DBus.Properties.Get” method in “org.bluez.Adapter1” interface to get the Name and MAC address of the Bluetooth controllers. When more then one Bluetooth controller is found, this example will list the Name and Address for all the controllers.

Similarly one can use the same method to get all the other properties of the controller (will be in next blog).

We can use dbus-send to explore the same information. Try the below command.

dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/' org.freedesktop.DBus.ObjectManager.GetManagedObjects

Caution:

One should be cautious when using GDBUS proxy based implementation in real application, because

  • If the service provider (Bluez in this case) is disappeared/crashed/restarted, then our proxy connection will be invalidated (in dangling state)
  • This can even happen when “StopWhenUnneeded=yes” option is specified in systemd service file “Unit” section.
  • Using such danging proxy will result in Segmentation fault.

To avoid such cases, one should watch “InterfacesRemoved” and “InterfacesAdded” generated on the “org.freedesktop.DBus.ObjectManager” interface to update the proxy to service path/name.