wiki:wireless/bluetooth

Version 15 (modified by Cale Collins, 6 years ago) ( diff )

removed broken link

https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Bluetooth.svg/220px-Bluetooth.svg.png

Goals

The main objective of this page is to describe Bluetooth from a Linux perspective and provide some general notes for specific applications such as reading a Bluetooth serial device or connecting to a Bluetooth HID.

Bluetooth

Bluetooth is a wireless protocol for short distances which encompasses the obvious benefit of low power. There is a concept of a Master device and a Slave device which is synonymous to infrastructure mode in 802.11a/b/g/n/ac (i.e. AP with several STA's). There can be a maximum of 7 active devices connected to the Master, but can have a total of 255 inactive connections. This Bluetooth network is called a Piconet. However, there are several options on how a Bluetooth network can be configured, several of which will be discussed below in the software section. There also exist several Bluetooth protocols which are defined by the Bluetooth SIG organization. This Wikipedia entry has a complete list of protocols. In order to fully appreciate the flexibility Bluetooth has to offer, the next few sections will be dedicated to these protocols and how to gain access to them.

All Bluetooth devices (both controllers and endpoints), like Ethernet devices, have a unique 6-byte MAC address.

Common Terminology:

  • stack - Refers to the software that implements the Bluetooth protocols
  • device - a Bluetooth end-point device
  • controller - Refers to the host controller attached to the CPU that can talk to bluetooth devices

Bluetooth Versions

Which version is used is dependent on the Hardware used as well as software. Be sure to check the specifications of the radio / device being used.

  • Bluetooth 4.0
    • Added Bluetooth Low Energy (BLE) protocol
  • Bluetooth 5.0
    • 4x the range ov Bluetooth 4.x (with lower throughput)
    • 2x the datarate of 4.x (1Mbps to 2Mbps)
    • Advertising packets move to 255 bytes
    • More advertising channels

Bluetooth Low Energy (BLE)

Also called Bluetooth LE, BLE, and Bluetooth Smart.

This is primarily used for data sensing, and not intended for continuous data-rate applications such as streaming audio or video. This enables new-use cases like beacons and sensors that have low-bandwidth periodic and sporodic data points. This also brings lower power to some use cases such as human interface devices (keyboard and mouse) input that is sporadic in nature, greatly increasing battery life for those devices.

Bluetooth Low Energy is much lower power than classic Bluetooth, possibly lasting months on a coincell. BLE is also cheaper for each peripheral devices.

BLE has many defined profiles, including specific profiles for the healthcare industry, sports and fitness and more. These are all based on the Generic Attribute Profile (GATT).

Bluetooth 4.x+ Devices will support Bluetooth Classic (aka BR/EDR) and/or Bluetooth Low Energy. Be away they may not support both and if you have a device that supports 'only' BLE it will not be able to use audio streaming such as the A2DP profile as support for BR/EDR is required for that.

Gateworks BSP Support

Gateworks supports multiple Board Support Packages. The following table shows details on bluetooth support for each:

BSP Product Families Drivers Stack
OpenWrt 14.08 All btusb/hciuart bluez3
Yocto Ventana btusb/hciuart bluez4
Android 5.1 Ventana btusb bluez5
OpenWrt 16.02 Ventana btusb/hciuart/bnep/rfcomm Fixed in commit ???

OpenWrt 14.08

Gateworks OpenWrt 14.08 supports Bluetooth via BlueZ 3.36

The following packages are installed by default on Gateworks firmware images:

  • btusb and bluetooth core kernel drivers
  • bluez-utils (bluetooth daemon and utils)
  • bluez-libs (bluetooth lib)
  • kmod-bluetooth (hci_uart, btusb, rfcomm, bnep, bluetooth, hidp, ath3k)

By default dbus-daemon and bluetooth daemon (hcid) are running and the controller is powered up with ISCAN and PSCAN enabled (discovery enabled) and the name is configured as 'OpenWrt' (the system hostname).

The dbus-send application is not installed by default (it is included in the dbus-util) package if you wish to install it, and no passkey agent is installed by default.

OpenWrt 14.08 supports UCI configuration for the Bluetooth daemon storing its configs in /etc/config/bluetooth. The default configuration provides:

  • hcid: enabled by default (controller discoverable via 'iscan enable; pscan enable' in /etc/bluetooth/hcid.conf)
  • hciattach: disabled by default
  • rfcomm: disabled by default
  • dund: disabled by default
  • pand: disabled by default

The Gateworks OpenWrt 14.08 BSP default firmware image provides support for the following:

  • most common USB based based BT controllers (via btusb, ath3k, btintel drivers)
  • HCI core protocol kernel support (HCI/L2CAP/SMP/SCO)
  • RFCOMM/BNPEP/HIDP kernel support
  • hciconfig/hcitool/sdptool/bluetoothd/rfcomm applications and daemones
  • scan/pair/discovery of bluetooth devices
  • Serial Port Profile (SP) via rfcomm app
  • Personal Area Network (PAN) Profile via pand app

A patch is needed to add the hidd application in order to support Human Interface Device Profile (HID):

diff --git a/utils/bluez-utils/Makefile b/utils/bluez-utils/Makefile
index 4f3f787..80d626f 100644
--- a/utils/bluez-utils/Makefile
+++ b/utils/bluez-utils/Makefile
@@ -43,6 +43,8 @@ CONFIGURE_ARGS += \
        --enable-network \
        --enable-usb \
        --enable-input \
+       --enable-hidd \
        --disable-audio \
        --with-bluez="$(STAGING_DIR)/usr/include" \
        --with-usb=yes \
@@ -58,9 +60,19 @@ endef

Yocto 1.8

Gateworks Yocto 1.8 BSP supports Bluetooth via BlueZ 4.101. Note that Yocto 1.3 also supported BlueZ 4 but the Yocto 1.6 and 1.7 BSP's do not have bluetooth enabled in the kernel.

The following packages are installed by default on Gateworks firmware images:

  • btusb and bluetooth core kernel drivers
  • bluez4 (bluetoothd daemon, libs, and utils)
  • bluez4-testtools
  • bluez-hcidump
  • gstreamer1.0-plugins-bad-bluze
  • libasound-module-bluez

The Gateworks Yocto 1.8 BSP default firmware images provides support for the following:

  • most common USB based based BT controllers (via btusb, ath3k, btintel drivers)
  • HCI core protocol kernel support (HCI/L2CAP/SMP/SCO)
  • RFCOMM/BNPEP/HIDP kernel support
  • hciconfig/hcitool/sdptool/bluetoothd/rfcomm applications and daemones
  • scan/discovery of bluetooth devices
  • Serial Port Profile (SP) via rfcomm app
  • Human Interface Device (HID) Profile via hidd dbus-send

By default the Bluetooth daemon (bluetoothd) is not running as there is no default init script. The dbus-send application exists and can be used for establishing HID connections. No passkey agent is installed by default for pairing (see how to install the pyton test tools for the bluez-simple-agent below).

To run bluetoothd:

bluetoothd

Installing Extra Bluetooth Packages

Depending on your needs, you may also need to install the test tools that are missing from the Yocto bluez package (and patch them to use the version of python-object installed on Yocto). This will add support for:

  • Personal Area Network (PAN) Profile (test-nap & test-network)
  • Simple Pairing agent (simple-agent)
    mkdir -p /usr/local/bin
    for i in simple-agent simple-service test-adapter test-audio test-device test-discovery test-input test-manager test-nap test-network test-oob test-serial; do \
      wget "http://git.kernel.org/cgit/bluetooth/bluez.git/plain/test/${i}?h=4.101" -O /usr/local/bin/bluez-${i}; \
      sed -i 's/from gi.repository import GObject/import gobject/' /usr/local/bin/bluez-${i}; \
      sed -i 's/mainloop = GObject.MainLoop/mainloop = gobject.MainLoop/' /usr/local/bin/bluez-${i}; \
      chmod +x /usr/local/bin/bluez-${i}; \
    done
    
  • On Ubuntu for example, these are packaged in the 'bluez' package already

If you are interested in using OBEX/FTP/OPP for binary file transfers you may want to build and install the obexftp and/or openobex Yocto packages.

Ubuntu 14.04

Ubuntu 14.04 uses the BlueZ 4.x stack and provides the following packages related to bluetooth:

  • bluez - core bluetooth daemon, utils and python test scripts (You will need to also install python-gobject and python-dbus if you wish to use the python test scripts)
  • bluez-compat - pand, hidd, dund for backwards compatibility with BlueZ 3 instructions and methods
  • bluez-btsco - Bluetooth SCO tool
  • bluez-cups - Bluetooth printer driver for CUPS
  • bluez-hcidump - Analyses Bluetooth HCI packets
  • bluez-tools - An alternative set of tools to manage bluetooth devices for linux (not documented here)
  • bluez-alsa - ALSA plugin for A2DP profile
  • bluez-gstreamer - GStreamer plugin for A2DP profile
  • pulseaudio-module-bluetooth - Bluetooth module for PulseAudio sound server (not documented here)
  • obexfs - mount filesystem of devices supporting OBEX FTP profile
  • obexftp - file transfer utility and daemon for devices supporting OBEX FTP profile
  • obexpushd - program for receiving files via OBEX OPP profile

For example:

  • to install all bluetooth related packages (174MB on top of a base Ubuntu system as described in ventana/ubuntu):
    apt-get install bluez bluez-compat bluez-alsa bluez-gstreamer bluez-utils bluez-tools python-gobject python-dbus
    
  • if you want the minimize you can just install bluez (which does depend on dbus, systemd, and python among some others) (14.9MB on top of a base Ubuntu system as described in ventana/ubuntu):
    apt-get install bluez
    

With the bluetooth packages above installed this allows for the following support:

  • most common USB based based BT controllers (via btusb, ath3k, btintel drivers)
  • HCI core protocol kernel support (HCI/L2CAP/SMP/SCO)
  • RFCOMM/BNPEP/HIDP kernel support
  • hciconfig/hcitool/sdptool/bluetoothd/rfcomm applications and daemones
  • scan/discovery of bluetooth devices
  • Serial Port Profile (SP) via rfcomm app
  • Human Interface Device (HID) Profile via hidd/dbus-send/bluez-test-input
  • Personal Area Network (PAN) Profile via pand app
  • File Transfer Protocol (FTP) Profile via obexftp and obxfs
  • Object Push Profile (OOP) via obexpushd
  • Advanced Audio Distribution Profile (A2DP) via bluez-alsa

Android

The Gateworks Android BSP replaces the standard Android Bluetooth 'bluedroid' stack with BlueZ. Please see Android Bluetooth for details on Android Bluetooth support.

Software (Linux)

A Bluetooth stack refers to the software that implements the protocol layers. This software can reside in the Linux kernel as well as userspace.

BlueZ (Standard Linux)

BlueZ is the Open Source Linux bluetooth protocol stack implemented in userspace using the Linux Bluetooth HCI core drivers. It also provides several tools for managing your Bluetooth connections, whether you're acting as a Slave (device) or Master (controller). BlueZ offers support for multiple Bluetooth devices, security, and several other features. It also provides several Protocols, or "Profiles", such as PAN, HID, and A2DP. The upcoming sections will discuss software generally compiled when building BlueZ

BlueZ general features:

  • flexible, efficient, modular architecture
  • support for multiple Bluetooth devices
  • multithreaded
  • hardware abstraction
  • standard socket interface to all layers

BlueZ consists of:

  • Linux kernel side:
    • Bluetooth Core:
      • HCI (Host Controller Interface) device and connection manager, schedule
      • SCO (Synchronous Connection Oriented) audio links
      • L2CAP (Logical Link Control and Adaptation Protocol)
      • SMP (Security Manager Protocol) on LE (Low Energy) links
    • HCI Device drivers (Interface to the hardware)
      • USB (btusb)
      • UART (hciuart)
      • SDIO
    • RFCOMM (RFCOMM Protocol for serial communication) Module (creates /dev/rfcomm serial devices)
    • BNEP (Bluetooth Network Encapsulation Protocol) Module (creates /sys/class/net/bnep network interfaces)
    • CMTP (CAPI Message Transport Protocol) Module
    • HIDP (Human Interface Device Protocol) Module (creates /sys/class/input devices)
  • Userspace side:
    • config and test utilities

Various linux distros will package BlueZ in a number of packages:

  • bluez - Bluetooth tools and daemons
  • bluez-alsa - Bluetooth ALSA support
  • bluez-btsco - Bluez Bluetooth SCO tool
  • bluez-cups - Bluetooth printder driver for CUPS
  • bluez-gstreamer - Bluetooth GStreamer support
  • bluez-hcidump - Analyze Bluetooth packets
  • bluez-tools - manage Bluetooth devices

While Bluez5 is the current stable release many Linux distros including Ubuntu 14.04, Gateworks Yocto 1.8 BSP still use Bluez4. See above regarding which Gateworks BSP's have what version of BlueZ

Recent BlueZ Version history:

  • BlueZ 5: Dec 2012
    • use standard D-Bus Properties and ObjectManager interfaces
    • different (and incompatible) D-Bus API (see the BlueZ 5 API porting-guide)
    • introduction of interface versions
    • simplification or removal of per-profile interfaces and the addition of a general org.bluez.Device1.Connect method
    • removal of org.bluez.Service interface
    • Dynamic device object creation during discovery
    • Introduction of an AgentManager1 interface
    • base path moved to "/org/bluez"
  • bluez-4.0: Aug 2008:
    • merged bluez-libs and bluez-utils together
    • main daemon now called bluetoothd (instead of hcid)
    • main config file is /etc/bluetoth/main.conf following an INI-style syntax
    • GLib no longer optional (eglib support fully removed)
    • old D-Bus API from 3.x series fully removed

Linux Kernel Drivers

The Linux Kernel defines a Bluetooth Host Controller Interface (HCI) for communication between hardware kernel drivers and userspace applications.

Several Linux kernel drivers implement a standard bluetooth HCI API in the form of a device node and ioctls. Each of these drivers implements support for a specific HCI presenting and a list of them can be found in /sys/class/bluetooth/hci*

The more standard HCI device drivers can be broken down into the following:

While Gateworks does not currently have bluetooth HCI's directly on its boards, our customers often add USB based HCI's in the form of miniPCIe combo cards (see hardware section below) or USB form-factor peripherals.

You can see what Bluetooth controllers are registered with the kernel by looking at the /sys/class/bluetooth directory:

# ls /sys/class/bluetooth
hci0

BlueZ 5.x

The Bluez5 bluetooth daemon (/usr/lib/bluez5/bluetooth/bluetoothd) runs in the background and the bluetoothctl application provides a Command Line Interface (CLI) to the daemon to perform all device and controller management.

NOTE: Bluez5 is not properly configured in Gateworks OpenWrt 16.02.

A typical session may look like this:

  1. Use list to list available controllers, and select <mac> to select one
  2. Turn the power on to a controller via power on (its off by default)
  3. Enable device discovery mode for the selected controller with scan on (its off by default)
    • New devices will be presented as they are found
    • Periodic messages will appear for each device found along with its signal strength (RSSI)
  4. You can list current devices with the devices command
  5. Turn the pairing agent on with the agent on command
  6. Pair a device via pair <mac>
    • If using a device without a PIN, you man need to manually trust the device before it can reconnect successfully. To do so use trust <mac>
  7. Establish a connection to the device via connect <mac>

Note that while in the CLI:

  • Tab completion works
  • Periodic asynchonous/unsolicited messages will appear for devices being scanned while scanning is on

Examples:

  • Pairing and connecting an HID keyboard:
    bluetoothctl
    [NEW] Controller 00:06:C6:FF:AD:1A ventana-0 [default]
    [bluetooth]# list
    Controller 00:06:C6:FF:AD:1A ventana-0 [default]
    [bluetooth]# show 00:06:C6:FF:AD:1A
    Controller 00:06:C6:FF:AD:1A
            Name: BlueZ 5.28
            Alias: ventana-0
            Class: 0x000000
            Powered: yes
            Discoverable: no
            Pairable: yes
            UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
            UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
            UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
            UUID: Handsfree                 (0000111e-0000-1000-8000-00805f9b34fb)
            Modalias: usb:v1D6Bp0246d051C
            Discovering: no
    
    [bluetooth]# select 00:06:C6:FF:AD:1A
    [bluetooth]# scan on
    Discovery started
    [CHG] Controller 00:06:C6:FF:AD:1A Discovering: yes
    [NEW] Device 54:46:6B:01:7B:2B 54-46-6B-01-7B-2B
    [CHG] Device 54:46:6B:01:7B:2B LegacyPairing: no
    [CHG] Device 54:46:6B:01:7B:2B Name: Bluetooth FAVI
    [CHG] Device 54:46:6B:01:7B:2B Alias: Bluetooth FAVI
    [bluetooth]# devices
    Device 54:46:6B:01:7B:2B Bluetooth FAVI
    [bluetooth]# pair 54:46:6B:01:7B:2B
    Attempting to pair with 54:46:6B:01:7B:2B
    Failed to pair: org.bluez.Error.ConnectionAttemptFailed
    [bluetooth]# pair 54:46:6B:01:7B:2B
    Attempting to pair with 54:46:6B:01:7B:2B
    [CHG] Device 54:46:6B:01:7B:2B Connected: yes
    [CHG] Device 54:46:6B:01:7B:2B Modalias: usb:v0A5Cp8502d011B
    [CHG] Device 54:46:6B:01:7B:2B UUIDs:
            00001000-0000-1000-8000-00805f9b34fb
            00001124-0000-1000-8000-00805f9b34fb
            00001200-0000-1000-8000-00805f9b34fb
    [CHG] Device 54:46:6B:01:7B:2B Paired: yes
    Pairing successful
    [CHG] Device 54:46:6B:01:7B:2B Connected: no
    [bluetooth]# connect 54:46:6B:01:7B:2B
    Attempting to connect to 54:46:6B:01:7B:2B
    [ 2178.501028] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [ 2178.507023] Bluetooth: HIDP socket layer initialized
    [CHG] Device 54:46:6B:01:7B:2B Connected: yes
    Connection successful
    
  • If using a device without a PIN you can manually trust the device in order to connect:
    [bluetooth]# trust 54:46:6B:01:7B:2B
    

To bring up a bluetooth controller (HCI) on boot, you can use a udev rule such as:

  • /etc/udev/rules.d/10-local.rules
    # bring up bluetooth host controller
    ACTION=="add", KERNEL=="hci0", RUN+="/usr/bin/hciconfig hci0 up"
    

After a suspend/resume cycle you can use a systemd service to bring the controller back up:

  • /etc/systemd/system/bluetooth-auto-power@.service
    [Unit]
    Description=Bluetooth auto power on
    After=bluetooth.service sys-subsystem-bluetooth-devices-%i.device suspend.target
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/hciconfig %i up
    
    [Install]
    WantedBy=suspend.target
    

Configuration:

  • bluetooth daemon configuruation is in /etc/bluetooth/main.conf:
    • AutoEnable=true in [Policy] section will bring up HCI on startup
  • bluetooth dbus configuration is in /etc/dbus-1/system.d/bluetooth.conf (can specify group there, defaults to lp group)

Notes:

  • must turn power on to controller by entering 'power on' (off by default) or by using hciconfig up
  • enter device desovery mode with 'scan on'
  • tab completion works in CLI
  • to pair, the bluetooth device must be in pairing mode (consult devices documentation). Typically this involves pressing or holding a button for a few seconds and results in a blinking blue LED to indicate the device is in pairing mode. Pairing typically stops after a minute or so depending on the device

References:

BlueZ 4.x

BlueZ 4.x was released in Aug 2008 with the following major changes over BlueZ 3.x:

  • Merged bluez-libs and bluez-utils together
  • Main daemon now called bluetoothd (instead of hcid)
  • Main config file is /etc/bluetooth/main.conf following an INI-style syntax
  • GLib no longer optional (eglib support fully removed)
  • Old D-Bus API from 3.x series fully removed
  • New D-Bus API is defined in doc/network-api.txt

The standard userpsace tools are:

  • bluetoothd - Bluetooth Daemon that manages all Bluetooth devices and configured via /etc/bluetooth/main.conf. Provides a number of services via D-Bus message bus system
  • hcitool
  • hciattach
  • hciconfig
  • l2ping
  • l2test
  • sdptool

some distros (ie Ubuntu) will provide a set of bluetooth compatibility binaries in a bluez-compat package that provide the following tools which were removed from bluez4:

  • Personal Area Network (PAN) networking daemon
  • Dial-Up Networking daemon
  • Bluetooth HID daemon

Configuration:

  • /etc/init/bluetooth.conf - bluetooth daemon init
  • /etc/bluetooth/main.conf - main bluetooth daemon config
    • name of device (when discoverable)
  • /etc/bluetooth/input.conf - configuration of the input service
  • /etc/bluetooth/audio.conf - configuration of the audio service (SCO routing: PCM or HCI)
  • /etc/bluetooth/network.conf - configuration of the network service (link encryption)
  • /etc/bluetooth/rfcomm.conf - configuration of rfcomm layer
  • /etc/bluetooth/serial.conf - configuration of serial (DUN tty, UID)

BlueZ 3.x

BlueZ 3.x has the following features:

  • uses dbus and system.d configured via /etc/dbus-1/system.d/bluetooth.conf
  • D-Bus API is defined in doc/network-api.txt
  • bluetooth daemon (hidc)
  • /etc/bluetooth/hcid.conf daemon configuration

The standard userspace tools are:

  • hcid - Bluetooth Daemon that manages all Bluetooth devices and configured via /etc/bluetooth/hcid.conf. Provides a number of services via D-Bus message bus system
  • hciconfig/hcitool/hciattach - HCI configuration tools
  • l2ping - Layer2 ping utility
  • sdptool - SDP browser
  • hidd - Human Interface Devices (HID) daemon
  • pand - Personal Area Network (PAN) networking daemon
  • dund - Dial-up networking daemon

D-Bus Message Bus System

The BlueZ stack uses the D-Bus message bus system which is a simple way for applications to talk to one another.

BlueZ 4 D-Bus API

The BlueZ 4 D-Bus API is defined in doc/network-api.txt. Some example usage using dbus-send:

  • First you need to get the path to the bluetooth controller you wish to use. We will assign it to a shell env variable and export it for future use:
    export BTADAPTER=`dbus-send --system --dest=org.bluez --print-reply / org.bluez.Manager.DefaultAdapter | tail -1 | sed 's/^.*"\(.*\)".*$/\1/'`
    
  • To introspect with you can use something like:
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.freedesktop.DBus.Introspectable.Introspect
    
  • To make your controller discoverable:
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.Adapter.SetProperty string:Discoverable variant:boolean:true
    
  • To disable discovery:
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.Adapter.SetProperty string:Discoverable variant:boolean:false
    
  • To list paired devices:
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.Adapter.ListDevices
    
  • To trust a device:
    dbus-send --system --dest=org.bluez --print-reply $BTADAPTER/dev_54_46_6B_01_7B_2B org.bluez.Device.SetProperty string:Trusted variant:boolean:true
    
  • To connect to an HID device (must pair first and can see the path above):
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER/dev_54_46_6B_01_7B_2B org.bluez.Input.Connect
    [ 2710.946655] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [ 2710.952642] Bluetooth: HIDP socket layer initialized
    method return sender=:1.3 -> dest=:1.13 reply_serial=2
    root@ventana:~# [ 2711.352289] hid-generic 0005:0A5C:8502.0001: unknown main item tag 0x0
    [ 2711.359234] input: Bluetooth FAVI as /devices/soc0/soc.0/2100000.aips-bus/2184000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0/bluetooth/hci0/hci0:42/0005:0A5C:8502.0001/input/input1
    [ 2711.374829] hid-generic 0005:0A5C:8502.0001: input: BLUETOOTH HID v1.1b Keyboard [Bluetooth FAVI] on 00:15:83:3d:0a:57
    evtest /dev/input/event1
    

BlueDroid (Android)

While Android used to use the standard Linux BlueZ stack, in 4.2.2 it switched to its own native stack called BlueDroid.

For Android Bluetooth details please see the [w iki:ventana/Android Android wiki pages].

Bluetooth Profiles

In order to use Bluetooth a device must be compatible with a subset of Bluetooth profiles for specific services. These profiles sit on top of the Bluetooth Core specification and protocols.

The way a device uses Bluetooth technology depends on its profile capabilities. The profiles provide standards which manufacturers follow to allow devices to be compatible.

A full list of profiles can be found here however here are some common ones are described in detail in the sections below

Serial Port Profile (SP)

The Serial Port Profile is based on ETSI 07.10 and the RFCOMM protocol. It emulates a serial cable to provide a simple substitude for existing RS-232 including control signals. This is the basis for DUN, FAX, HSP and AVRCP profiles. SPP maximum payload capacity is 128 bytes.

An example of a device using this profile would be a Bluetooth GPS device.

The Linux kernel has an RFCOMM driver that ties into the bluetooth stack and registers /dev/rfcomm<n> device nodes when necessary.

Use the rfcomm utility from the bluez package to listen for or connect so bluetooth connections. It is not necessary to be paired or trusted in this case.

For example, to create a serial link between two Linux systems:

  • Machine1: SP server
    # hciconfig hci0 piscan # make us discoverable
    # hciconfig hci0 -a
    hci0:   Type: BR/EDR  Bus: USB
            BD Address: 00:02:72:C9:56:47  ACL MTU: 1021:8  SCO MTU: 64:1
            UP RUNNING PSCAN ISCAN 
            RX bytes:7258 acl:121 sco:0 events:203 errors:0
            TX bytes:4561 acl:119 sco:0 commands:91 errors:0
            Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
            Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
            Link policy: RSWITCH SNIFF 
            Link mode: SLAVE ACCEPT 
            Name: 'ventana-0'
            Class: 0x000100
            Service Classes: Unspecified
            Device Class: Computer, Uncategorized
            HCI Version: 4.0 (0x6)  Revision: 0x1000
            LMP Version: 4.0 (0x6)  Subversion: 0x220e
            Manufacturer: Broadcom Corporation (15)
    
    # sdptool add SP --channel=1 # advertise an SP service record for channel 1
    # rfcomm listen hci0 1 # listen on hci0 for SP requests on channel 1 (cntl-C to exit)
    Waiting for connection on channel 1
    
  • Machine2: SP client
    # hciconfig hci0 up
    # hcitool scan
    Scanning ...
            00:02:72:C9:56:47       ventana-0
    # sdptool search SP
    Inquiring ...
    Searching for SP on 00:02:72:C9:56:47 ...
    Service Name: Serial Port
    Service Description: COM Port
    Service Provider: BlueZ
    Service RecHandle: 0x10000
    Service Class ID List:
      "Serial Port" (0x1101)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 1
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Serial Port" (0x1101)
        Version: 0x0100
    
    # rfcomm connect hci0 00:02:72:C9:56:47 1
    Press CTRL-C for hangup
    
    • once a connection is established the rfcomm processes on both the client and server will display 'Press CTRL-C for hangup' at which point they will create a /dev/rfcomm0 node that can be used with any terminal application. When you wish to close the connection kill the rfcomm process.
    • terminal characterists such as baudrate and line control have no effect on rfcomm devices

You can configure the bluetooth daemon to bind to a device on startup via /etc/bluetooth/rfcomm.conf. For example: For example:

rfcomm0 {
       # Automatically bind the device at startup
       bind no;
       # Bluetooth address of the device
       device 00:11:22:33:44:55;
       # RFCOMM channel for the connection (check your GPS docs for details)
       channel 1;
       # Description of the connection
       comment "Bluetooth GPS";
}

Restart the Bluetooth daemon or services following this change:

# /etc/init.d/bluetoothd restart

You should now be able to bind the GPS to /dev/rfcomm0 like this:

# rfcomm bind 0

And you can confirm the connection:

# rfcomm
rfcomm0: 00:11:22:33:44:55 channel 1 clean

Now you can use /dev/rfcomm0 like any other serial device (ie 'stty', 'screen', etc):

# stty -F /dev/rfcomm0 115200 # set baudrate
# cat /dev/rfcomm0
$GPGGA,111748.000,5907.6964,N,01121.1787,E,1,06,1.2,57.7,M,40.1,M,,0000*6F
$GPRMC,111748.000,A,5907.6964,N,01121.1787,E,0.00,94.94,160807,,,A*50
$GPVTG,94.94,T,,M,0.00,N,0.0,K,A*3D

References:

Headset Profile (HSP)

The Headset Profile (HSP) was encoropred in the initial Bluetooth specification for mono headsets. If a microphone is present on a stereo headphone device, it uses HSP for the audio channel. HSP uses a RFCOMM channel for control based on standard AT commands with bluetooth specific extensions for volume control and accept/reject buttons. The transport for audio is an SCO channel which allows a single (mono) 8kHz PCM encoded using Continuous Variable Slope Delta (CVSD) modulation amounting to 64kbps. This audio transferred over SCO can be provided to the HCI hardware driver (typical) or in highly embedded applications directly to an audio codec chip via a PCM back-channel depending on the bluetooth chipset.

Handsfree Profile (HFP)

The Handsfree profile (HFP) is a more advanced version of HSP but also designed for mono headsets. It adds support for additional remote functions such as dialing and later versions add optional support for better-quality mono audio using the SBC codec.

Human Interface Device Profile (HID)

The Human Interface Device Profile (HID) is implemented with a kernel module (hidp) that registers a Linux Input device upon request from the bluetooth daemon.

Configuration of HID depends upon the version of BlueZ (see BSP table above). In general the HID device must be paired with (or trusted) and the bluetooth daemon must register it for use with the hidp kernel module which creates a Linux Input device that can be seen in /sys/class/input.

Notes:

  • BT HID devices (ie keyboard or mouse) and controllers (HCI) need to be paired once. See Pairing for more details.
  • Once connected a /dev/input/event<n> device node will be registered and can be used for Linux Input events as long as the connection persists.
  • You can test the connection (if connected through a TTY session) by running a tool such as evtest or event_test which will show you events on Linux Input devices.

BlueZ 5:

  • The bluetoothctl utility allows for HID's to connect to the Bluetooth adapter. This provides a Command Line Interface (CLI):
    # bluetoothctl
    [NEW] Controller 00:06:C6:FF:AD:1A ventana-0 [default]
    [bluetooth]# power on
    Changing power on succeeded
    [CHG] Controller 00:06:C6:FF:AD:1A Powered: yes
    [bluetooth]# scan on
    Discovery started
    [CHG] Controller 00:06:C6:FF:AD:1A Discovering: yes
    [NEW] Device 54:46:6B:01:7B:2B 54-46-6B-01-7B-2B
    [CHG] Device 54:46:6B:01:7B:2B LegacyPairing: no
    [CHG] Device 54:46:6B:01:7B:2B Name: Bluetooth FAVI
    [CHG] Device 54:46:6B:01:7B:2B Alias: Bluetooth FAVI
    [bluetooth]# devices
    Device 54:46:6B:01:7B:2B Bluetooth FAVI
    [bluetooth]# pair 54:46:6B:01:7B:2B
    Attempting to pair with 54:46:6B:01:7B:2B
    [CHG] Device 54:46:6B:01:7B:2B Connected: yes
    [CHG] Device 54:46:6B:01:7B:2B Modalias: usb:v0A5Cp8502d011B
    [CHG] Device 54:46:6B:01:7B:2B UUIDs:
            00001000-0000-1000-8000-00805f9b34fb
            00001124-0000-1000-8000-00805f9b34fb
            00001200-0000-1000-8000-00805f9b34fb
    [CHG] Device 54:46:6B:01:7B:2B Paired: yes
    Pairing successful
    [CHG] Device 54:46:6B:01:7B:2B Connected: no
    [bluetooth]# connect 54:46:6B:01:7B:2B
    Attempting to connect to 54:46:6B:01:7B:2B
    [ 2178.501028] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [ 2178.507023] Bluetooth: HIDP socket layer initialized
    [CHG] Device 54:46:6B:01:7B:2B Connected: yes
    Connection successful
    [bluetooth]# exit
    

BlueZ 4:

  • Using D-Bus via the dbus-send to interact with bluetoothd (requires pairing):
    # hciconfig hci0 up
    # hcitool -i hci0 scan
    Scanning ...
            54:46:6B:01:7B:2B       Bluetooth FAVI
    # sdptool search HID # search for and show all discoverable devices advertising an HID service
    Inquiring ...
    Searching for HID on 54:46:6B:01:7B:2B ...
    Service Name: Broadcom Bluetooth Wireless  Keyboard                        
    Service Description: Keyboard
    Service Provider: Broadcom Corp.  
    Service RecHandle: 0x10000
    Service Class ID List:
      "Human Interface Device" (0x1124)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 17
      "HIDP" (0x0011)
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Human Interface Device" (0x1124)
        Version: 0x0100
    
    # bluez-simple-agent hci0 54:46:6B:01:7B:2B  # request pairing (specify pin code when requested then enter this code followed by a Enter on the keyboard to pair)
    RequestPinCode (/org/bluez/471/hci0/dev_54_46_6B_01_7B_2B)
    Enter PIN Code: 0000
    Release
    New device (/org/bluez/471/hci0/dev_54_46_6B_01_7B_2B)
    # export BTADAPTER=`dbus-send --system --dest=org.bluez --print-reply / org.bluez.Manager.DefaultAdapter | tail -1 | sed 's/^.*"\(.*\)".*$/\1/'` # get the adapter path
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.Adapter.ListDevices  # list paired adapters 
    # dbus-send --system --dest=org.bluez --print-reply $BTADAPTER/dev_54_46_6B_01_7B_2B org.bluez.Input.Connect # connect to an adapter
    method return sender=:1.3 -> dest=:1.8 reply_serial=2
    [ 2710.946655] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [ 2710.952642] Bluetooth: HIDP socket layer initialized
    [ 2711.352289] hid-generic 0005:0A5C:8502.0001: unknown main item tag 0x0
    [ 2711.359234] input: Bluetooth FAVI as /devices/soc0/soc.0/2100000.aips-bus/2184000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0/bluetooth/hci0/hci0:42/0005:0A5C:8502.0001/input/input1
    [ 2711.374829] hid-generic 0005:0A5C:8502.0001: input: BLUETOOTH HID v1.1b Keyboard [Bluetooth FAVI] on 00:15:83:3d:0a:57
    evtest /dev/input/event1
    
  • Using D-Bus via bluez-test-input python script (requires pairing):
    # hciconfig hci0 up
    # hcitool -i hci0 scan
    Scanning ...
            54:46:6B:01:7B:2B       Bluetooth FAVI
    # bluez-simple-agent hci0 54:46:6B:01:7B:2B  # request pairing (specify pin code when requested then enter this code followed by a Enter on the keyboard to pair)
    RequestPinCode (/org/bluez/471/hci0/dev_54_46_6B_01_7B_2B)
    Enter PIN Code: 0000
    Release
    New device (/org/bluez/471/hci0/dev_54_46_6B_01_7B_2B)
    # bluez-test-input connect 54:46:6B:01:7B:2B
    [ 1654.853401] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [ 1654.859353] Bluetooth: HIDP socket layer initialized
    [ 1655.633452] hid-generic 0005:0A5C:8502.0001: unknown main item tag 0x0
    [ 1655.640391] input: Bluetooth FAVI as /devices/soc0/soc.0/2100000.aips-bus/2184000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0/bluetooth/hci0/hci0:12/0005:0A5C:8502.0001/input/input1
    [ 1655.655952] hid-generic 0005:0A5C:8502.0001: input: BLUETOOTH HID v1.1b Keyboard [Bluetooth FAVI] on 00:02:72:c9:56:47
    
  • Use hidd from the bluez-compat package to connect (see below)
  • In all of the above cases the kernel has registered a new input device input1 (/sys/class/input/input1, /dev/input/event1)

BlueZ 3:

  • Use hidd from the bluez package to connect (does not require pairing, or more specifically performs automatic pairing for you):
    # hciconfig hci0 up
    # hcitool -i hci0 scan # show all discverable devices
    Scanning ...
            54:46:6B:01:7B:2B       Bluetooth FAVI
    # sdptool search HID # search for and show all discoverable devices advertising an HID service
    Inquiring ...
    Searching for HID on 54:46:6B:01:7B:2B ...
    Service Name: Broadcom Bluetooth Wireless  Keyboard                        
    Service Description: Keyboard
    Service Provider: Broadcom Corp.  
    Service RecHandle: 0x10000
    Service Class ID List:
      "Human Interface Device" (0x1124)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 17
      "HIDP" (0x0011)
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Human Interface Device" (0x1124)
        Version: 0x0100
    
    # hidd --connect 54:46:6B:01:7B:2B
    [28013.797391] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
    [28013.798954] Bluetooth: HIDP socket layer initialized
    [28018.300685] hid-generic 0005:0A5C:8502.0001: unknown main item tag 0x0
    [28018.309052] input: Broadcom Bluetooth Wireless  Keyboard                         as /devices/soc0/soc.0/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1/1-1.1:1.0/bluetooth/hci0/hci0:40/0005:0A5C:8502.0001/input/input5
    [28018.309767] hid-generic 0005:0A5C:8502.0001: input: BLUETOOTH HID v1.1b Keyboard [Broadcom Bluetooth Wireless  Keyboard                        ] on 00:15:83:6b:e2:bd
    
    • use hidd unplug <bdaddr> to disconnect the HID connection
    • use hidd kill <bdaddr> to kill the HID connection
    • use hidd show to show all HID connections
    • use hidd search to search for HID devices in range and automatically connect to them
    • use -i <hciX|bdaddr> to specify the bluetooth controller

Personal Area Network Device Profile (PAN)

The Personal Area Network Device Profile (PAN) allows encapsulating IP over bluetooth using the Bluetooth Network Encapsulation Protocol (BNEP). The kernel bnep module (CONFIG_BT_BNEP) is responsible for registering a bnep<n> network interface when requested by the Bluetooth daemon. You do not need to use pairing for PAN connections. Once a PAN connection is active and you have a bnep<n> interface you can use standard networking tools to configure and/or bridge the interface.

There are three PAN roles:

  • NAP - Network Access Point
  • PANU - PAN User (client to a PAN NAP)
  • GN - Group Network (adhoc based)

Configuration of PAN depends upon the version of BlueZ (see BSP table above).

BlueZ 5:

  • Using D-Bus via a bt-pan python script and the bluetoothctl CLI (requires python, python-dbus):
    • Machine1: server / NAP
      # bluetoothctl 
      [NEW] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      [bluetooth]# power on
      Changing power on succeeded
      [CHG] Controller 00:02:72:C9:56:47 Powered: yes
      [bluetooth]# discoverable on
      Changing discoverable on succeeded
      [CHG] Controller 00:02:72:C9:56:47 Discoverable: yes
      [bluetooth]# agent on
      Agent registered
      [bluetooth]# default-agent
      Default agent request successful
      [NEW] Device 00:15:83:3D:0A:57 yocto18-0
      Request PIN code
      [agent] Enter PIN code: 0000
      [CHG] Device 00:15:83:3D:0A:57 Paired: yes
      [CHG] Device 00:15:83:3D:0A:57 Connected: no
      [bluetooth]# paired-devices
      Device 00:15:83:3D:0A:57 yocto18-0
      [bluetooth]# trust 00:15:83:3D:0A:57
      [CHG] Device 00:15:83:3D:0A:57 Trusted: yes
      Changing 00:15:83:3D:0A:57 trust succeeded
      [bluetooth]# exit
      Agent unregistered
      [DEL] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      # sdptool add NAP # advertise NAP service
      # brctl addbr br0
      # wget https://raw.githubusercontent.com/mk-fg/fgtk/master/bt-pan
      # chmod +x bt-pan
      # ./bt-pan --debug server br0 &
      DEBUG:root:Using local device (addr: 00:02:72:C9:56:47): /org/bluez/hci0
      DEBUG:root:Registered uuid 'nap' with bridge/dev: br0 / 00:02:72:C9:56:47
      # ifconfig br0
      br0       Link encap:Ethernet  HWaddr 00:02:72:c9:56:47  
                BROADCAST MULTICAST  MTU:1500  Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:0 
                RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
      
      # brctl show br0
      bridge name     bridge id               STP enabled     interfaces
      br0             8000.000272c95647       no              bnep0
      
      • first we used bluetoothctl to bring up the controller, make it discoverable, and pair with and trust the client. Next we created a bridge, fetched the bt-pan python script and used it to resiter a NAP server which registers a bnep0 network interface with Linux upon successful connection with a PANU client. The bnpeg0 network interface will be added to the bridge. Make sure you use standard networking tools to configure the bridge as desired.
    • Machine2: client / PANU
      # bluetoothctl 
      [NEW] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      [bluetooth]# power on
      Changing power on succeeded
      [bluetooth]# discoverable on
      Changing discoverable on succeeded
      [CHG] Controller 00:02:72:C9:56:47 Discoverable: yes
      [bluetooth]# agent on
      Agent registered
      [bluetooth]# default-agent
      Default agent request successful
      [NEW] Device 00:15:83:6B:E2:BD ventana-trusty-0
      Request confirmation
      [agent] Confirm passkey 744563 (yes/no): yes
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 00001112-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 00001116-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 0000111e-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 0000111f-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
      [CHG] Device 00:15:83:6B:E2:BD Paired: yes
      [CHG] Device 00:15:83:6B:E2:BD Connected: no
      [bluetooth]# trust 00:15:83:6B:E2:BD
      [CHG] Device 00:15:83:6B:E2:BD Trusted: yes
      Changing 00:15:83:6B:E2:BD trust succeeded
      [bluetooth]# exit
      Agent unregistered
      [DEL] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      root@xenial:~# bluetoothctl 
      [NEW] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      [NEW] Device 00:15:83:6B:E2:BD ventana-trusty-0
      [bluetooth]# paired-devices
      Device 00:15:83:6B:E2:BD ventana-trusty-0
      [bluetooth]# exit 
      [DEL] Controller 00:02:72:C9:56:47 BlueZ 5.37 [default]
      # sdptool search NAP
      Inquiring ...
      Searching for NAP on 00:15:83:6B:E2:BD ...
      Service Name: Network Access Point
      Service Description: BlueZ PAN Service
      Service Provider: BlueZ PAN
      Service RecHandle: 0x10006
      Service Class ID List:
        "Network Access Point" (0x1116)
      Protocol Descriptor List:
        "L2CAP" (0x0100)
          PSM: 15
        "BNEP" (0x000f)
          Version: 0x0100
          SEQ16: 800 806
      Language Base Attr List:
        code_ISO639: 0x656e
        encoding:    0x6a
        base_offset: 0x100
      Profile Descriptor List:
        "Network Access Point" (0x1116)
          Version: 0x0100
      
      # wget https://raw.githubusercontent.com/mk-fg/fgtk/master/bt-pan
      # chmod +x bt-pan
      # ./bt-pan --debug client 00:15:83:6B:E2:BD
      DEBUG:root:Using local device (addr: 00:02:72:C9:56:47): /org/bluez/hci0
      DEBUG:root:Using remote device (addr: 00:15:83:6B:E2:BD): /org/bluez/hci0/dev_00_15_83_6B_E2_BD
      DEBUG:root:Connected to network (dev_remote: /org/bluez/hci0/dev_00_15_83_6B_E2_BD, addr: 00:15:83:6B:E2:BD) uuid 'nap' with iface: bnep0
      DEBUG:root:Finished
      root@xenial:~# ifconfig bnep0
      bnep0     Link encap:Ethernet  HWaddr 00:02:72:c9:56:47  
                inet6 addr: fe80::202:72ff:fec9:5647/64 Scope:Link
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:16 (16.0 B)  TX bytes:148 (148.0 B)
      
      
      • first we used bluetoothctl to pair with and trust the client. Next we fetched the bt-pan python script and used it to connect to the client which registers a bnep0 network interface with Linux upon successful connection with a NAP server. Make sure you use standard networking tools to configure the bridge as desired.

BlueZ 4:

  • Using the pand tool from the bluez-compat package (see below)
    • to use the pand application for BlueZ 4.x you must disable the internal network plugin in its bluetooth daemon. To do this add a 'DisablePlugins=network' to /etc/bluetooth/main.conf under the [General] section and restart the bluetooth daemon)
  • Using the bt-network application from the bluez-tools package (requires pairing):
    • Machine1: server / NAP:
      # hciconfig hci0 up # bring up controller
      # hciconfig hci0 piscan # make discoverable
      # brctl addbr br0 # add a bridge
      # bt-network --server nap br0 # run NAP service
      NAP server registered
      
    • Machine2: client / PANU:
      # hciconfig hci0 up # bring up controller
      # hciconfig hci0 piscan # make discoverable
      # sdptool search NAP # search for NAP service
      # bt-network --connect 00:02:72:C9:56:47 nap &
      

BlueZ 3:

  • Using the pand tool from the bluez package:
    • to use the pand application for BlueZ 4.x you must disable the internal network plugin in its bluetooth daemon. To do this add a 'DisablePlugins=network' to /etc/bluetooth/main.conf under the [General] section and restart the bluetooth daemon)
    • Machine1: server / NAP:
      # hciconfig hci0 up # bring up bluetooth controller
      # hciconfig hci0 piscan # make discoverable
      # pand --listen --role NAP --master
      
      • Once connected to a PANU you will see a message such as pand[872]: New connection from 00:15:83:3D:0A:57 at bnep0
    • Machine2: client / PANU:
      # hciconfig hci0 up # bring up bluetooth controller
      # hcitool -i hci0 scan # show all discoverable bluetooth devices
      Scanning ...
              00:15:83:6B:E2:BD       ventana-trusty-0
      # sdptool search NAP # show all discoverable bluetooth devices advertising NAP service
      Inquiring ...
      Searching for NAP on 00:15:83:6B:E2:BD ...
      Service Name: Network Access Point
      Service Description: BlueZ PAN Service
      Service Provider: BlueZ PAN
      Service RecHandle: 0x10008
      Service Class ID List:
        "Network Access Point" (0x1116)
      Protocol Descriptor List:
        "L2CAP" (0x0100)
          PSM: 15
        "BNEP" (0x000f)
          Version: 0x0100
          SEQ16: 800 806
      Language Base Attr List:
        code_ISO639: 0x656e
        encoding:    0x6a
        base_offset: 0x100
      Profile Descriptor List:
        "Network Access Point" (0x1116)
          Version: 0x0100
      
      # pand --connect 00:15:83:6B:E2:BD --service NAP --nodetach
      pand[717]: Bluetooth PAN daemon version 4.101
      pand[717]: Connecting to 00:15:83:6B:E2:BD
      pand[717]: bnep0 connected
      
    • You can remove the --nodetach to run as a daemon (in which case you won't see the pand messages on the console indicating the connection status)
    • You can use pand --role PANU --search to search for and auto-connect to the first NAP server found:
      # pand --role PANU --search --nodetach
      pand[723]: Bluetooth PAN daemon version 4.101
      pand[723]: Inquiring
      pand[723]: Searching for NAP on 00:15:83:6B:E2:BD
      pand[723]: Connecting to 00:15:83:6B:E2:BD
      pand[723]: bnep0 connected
      
  • Using D-Bus messages via dbus-send:
    • Machine1: server / NAP:
      export BTADAPTER=`dbus-send --system --dest=org.bluez --print-reply / org.bluez.Manager.DefaultAdapter | tail -1 | sed 's/^.*"\(.*\)".*$/\1/'` # get the adapter path
      
      dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.NetworkHub.SetProperty string:Enabled variant:boolean:true
      

Object Push Profile (OPP)

The Object Push Profile (OPP) is used to send binary data objects. An OPP server is needed to receive files via OPP. OOP defines the roles of 'push server' and 'push client':

  • Push Server - the device that provides an object exchange server.
  • Push Client - the device that pushes and pulls objects to and from the Push Server.

You can use the obexpushd tool to create an OPP Push Server and listen for incoming files. You can use the obexftp tool as a Push Client to send files to a Push Server.

Devices do not need to be previously paired for the OPP profile. Note that the FTP profile is much more capable profile.

Android devices:

  • Several Android applications can use OPP to push files to a device with an OPP Push Server. For example, Google photos and the Google Camera app use this when you select the 'share icon' when viewing an image followed by the 'Bluetooth' icon (at which point it will show you all bluetooth devices that provide an OPP Push server)
  • There are several applications in the Google Play Store that provide the ability to push files to an 'OBEX OPP' server such as 'Bluetooth File Transfer' by Medieval Software: Note that by default this application enables an OOP and an FTP server without authentication (but pairing is required) while the app is running.

Examples:

  • Discover devices providing a Push Server:
    # sdptool search OPUSH
    
  • Receive a file via obexpushd:
    # hciconfig hci0 piscan # make sure we are discoverable
    # obexpushd -B5 -o /tmp -n # start Push Server on bluetooth channel 9 using /tmp as a directory store
    obexpushd 0.11.2 Copyright (C) 2006-2010 Hendrik Sattler
    This software comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it
    under certain conditions.
    Warning: local character set is not Unicode.
    Listening on bluetooth/[00:00:00:00:00:00]:5
    Creating file "/tmp/0001.patch"
    ^C
    
    • remove the -n to run in the background
    • above shows a file accepted called 00001.patch
  • Binary file transfer to a device providing an OBEX OPP Push server using obexftp:
    # sdptool search OPUSH
    Inquiring ...
    Searching for OPUSH on 00:15:83:6B:E2:BD ...
    Service Name: OBEX Object Push
    Service Description: a free OBEX server
    Service Provider: obexpushd
    Service RecHandle: 0x10006
    Service Class ID List:
      "OBEX Object Push" (0x1105)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 5
      "OBEX" (0x0008)
    Profile Descriptor List:
      "OBEX Object Push" (0x1105)
        Version: 0x0100
    
    # obexftp --bluetooth 00:15:83:6B:E2:BDE --channel 5 --put file.pdf
    Connecting..\done
    Tried to connect for 129ms
    Sending "file.pdf".../done
    Disconnecting..-done
    

File Transfer Profile (FTP)

Provides the capability to browse, manipulate and transfer objects (files and folders) in an object store (file system) of another system. This uses GOEP as a basis.

You can use this with the obexftp and obexfs Linux tools when paired with the right service:

  • obexftp - a file transfer protocol client using the OBEX FTP profile
  • obexfs - a FUSE-based filesystem that uses the OBEX FTP profile to connect to an OBEX server

Devices need to be previously paired (see pairing).

Android devices:

  • There are several applications in the Google Play Store that provide an 'OBEX FTP' server:
    • 'Bluetooth File Transfer' by Medieval Software: Note that by default this application enables an OOP and an FTP server without authentication (but pairing is required) while the app is running.

Examples:

  • Discover devices providing a FTP service:
    # sdptool search FTP
    
  • List available files on a device providing an OBEX FTP service using obexftp:
    # sdptool search FTP # search for devices advertising FTP profile
    Inquiring ...
    Searching for FTP on 98:E7:F5:A1:A1:EE ...
    Service Name: OBEX FTP
    Service RecHandle: 0x1000d
    Service Class ID List:
      UUID 128: 00001106-0000-1000-8000-00805f9b34fb
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 6
    
    # obexftp --bluetooth 98:E7:F5:A1:A1:EE --channel 6 --list
    
  • Delete a file from a device providing an OBEX FTP service using obexftp:
    # sdptool search FTP # search for devices advertising FTP profile
    Inquiring ...
    Searching for FTP on 98:E7:F5:A1:A1:EE ...
    Service Name: OBEX FTP
    Service RecHandle: 0x1000d
    Service Class ID List:
      UUID 128: 00001106-0000-1000-8000-00805f9b34fb
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 6
    
    # obexftp --bluetooth 98:E7:F5:A1:A1:EE --channel 6 --delete
    
  • Binary file transfer to a device providing an OBEX FTP service using obexftp:
    # sdptool search FTP # search for devices advertising FTP profile
    Inquiring ...
    Searching for FTP on 98:E7:F5:A1:A1:EE ...
    Service Name: OBEX FTP
    Service RecHandle: 0x1000d
    Service Class ID List:
      UUID 128: 00001106-0000-1000-8000-00805f9b34fb
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 6
    
    # obexftp --bluetooth 98:E7:F5:A1:A1:EE --channel 6 --put file.pdf
    Connecting..\done
    Tried to connect for 129ms
    Sending "file.pdf".../done
    Disconnecting..-done
    
  • Binary file transfer from a device providing an OBEX FTP service using obexftp:
    # sdptool search FTP # search for devices advertising FTP profile
    Inquiring ...
    Searching for FTP on 98:E7:F5:A1:A1:EE ...
    Service Name: OBEX FTP
    Service RecHandle: 0x1000d
    Service Class ID List:
      UUID 128: 00001106-0000-1000-8000-00805f9b34fb
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 6
    
    # obexftp --bluetooth 98:E7:F5:A1:A1:EE --channel 6 --get file.pdf
    Connecting..\done
    Tried to connect for 60ms
    Receiving "file.pdf".../done
    Disconnecting..-done
    
  • Run an OBEX FTP server using obexftpd:
    # hciconfig hci0 piscan # make us discoverable
    # cd /tmp
    # obexftpd -b5 # start OBEX FTP server via bluetooth channel 5
    
  • Mount a filesystem from an 'OBEX FTP' service using obexfs:
    # sdptool search FTP # search for devices advertising FTP profile
    Inquiring ...
    Searching for FTP on 98:E7:F5:A1:A1:EE ...
    Service Name: OBEX FTP
    Service RecHandle: 0x1000d
    Service Class ID List:
      UUID 128: 00001106-0000-1000-8000-00805f9b34fb
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 6
    
    # obexfs --bluetooth 98:E7:F5:A1:A1:EE --channel 6 /mnt
    # mount | grep obexfs
    obexfs on /mnt type fuse.obexfs (rw,nosuid,nodev)
    # ls /mnt
    Alarms    LinkLocalStorage  Notifications  UnityAdsVideoCache  file.pdf
    Android   Logs              Pictures       camera-p.jpg        games
    DCIM      Movies            Podcasts       docs                panoramas
    Download  Music             Ringtones      foo
    

Note that the obexftp application also supports pushing files to an OBEX OPP server (see above).

Advanced Audio Distribution Profile (A2DP)

The Advanced Audio Distribution Profile (A2DP) is a bluetooth profile that many devices support and is what is used for high fidelity headphone stereo audio. All stereo headphones support A2DP and AVRCP. The Logical Link Controller and Adaptation Protocol (L2CAP) is used in conjunction with the Audio/Video Distribution Transport Protocol (AVDTP) for control and streaming audio. This defines a binary protocol and binary streaming protocol based on RTP. A royalty free Subband-codec (SBC) is included i n the A2DP spec as a mandatory protocol but it is possible for BT devices to also optionally support MP3, AAC or other codecs.

The quality of audio sent to a wireless headphone is determined by the codec. After the audio source (ie phone) selects the appropriate profile it chooses a codec which the audio sink (ie headhpone) the decodes for playback. Although it is theoretically possible to send mp3's or any other digital format straight to the headphones over Bluetooth instead the A2DP profile specifies its own set of audio codecs:

  • SBC (Subband Coding) - the mandatory default codec for A2DP supported by all Bluetooth stereo devices. It was deisgned to provide reasonably good audio quality over the limited bandwidth of Bluetooth without heavy processing requirements. SBC is capable of bitrates up to about 328kbps at 44.1kHz sampling which is not far off from the maximum for mp3 encoding though mp3 is superior to SBC in terms of audio quality given similar bitrates. SBC is also capable of mid and low quality streams which sound quite compressed to the ears and are unacceptable for music streaming and sound quality varies widly between different SBC implementations.
  • aptX is a proprietary audio codec developed for demanding audio applications designed to encode CD-quality (16bit 44.1kHz) or better (up to 24bit 96kHz) without loss of quality using a slightly higher data rate but more efficient compared to SBC. The aptX codec is not required by A2DP and currently aptX is only supported by CSR chipsets typically used in high-end Android devices. Both the headphone and the source must support aptX and if not the default SBC codec will be used instead. Currently aptX support is limited to mostly high-end Android smartphones and Hi-Fi wireless devices.
  • AAC (Advanced Audio Coding) is a popular codec in general designed to achieve better sound quality than mp3 at similar bit rates. Unlike aptX it is supported by iOS devices (Apple implements AAC over bluetooth at about 250kbps) which should compete in fidelity. Support for AAC is not common in bluetooth devices.

Requirements:

  • userspace bluteooth-alsa libs (libasound_module_{pcm,ctl}_bluetooth.so) (Ubuntu: bluez-alsa, Yocto: libasound-module-bluez)

The process to connect Bluetooth A2DP devices differs based on the version of the BlueZ stack you are using as well as the audio back-end that you are using:

  • ALSA: bluez-alsa (Ubuntu) / libasound-module-bluez (Yocto) package providing libasound_module_{pcm,ctl}_bluetooth.so
  • GStreamer: bluez-gstreamer (Ubuntu) providing libgstbluetooth.so / gstreamer1.0-plugins-bad-bluez (Yocto) providing libgstbluez.so
  • PulseAudio: pulseaudio-module-blueeooth (Ubuntu) providing module-bluetooth-{policy,device,discover,proximity}.so

BlueZ 4.x / ALSA:

  • Using Bluetooth headphones to playback audio from Linux device (Linux device is an A2DP Source and connecting to an A2DP Sink)
  1. Identify (put headphones into pairing mode)
    # hcitool scan
    Scanning ...
            A4:15:66:5B:B9:79       Motorola Buds
    # sdptool search A2SNK
    Inquiring ...
    Searching for A2SNK on A4:15:66:5B:B9:79 ...
    Service Provider: AVExtension_Device
    Service RecHandle: 0x10002
    Service Class ID List:
      "Audio Sink" (0x110b)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 25
      "AVDTP" (0x0019)
        uint16: 0x0100
    Profile Descriptor List:
      "Advanced Audio" (0x110d)
        Version: 0x0100
    
    
  2. Pair
    # bluez-simple-agent hci0 A4:15:66:5B:B9:79
    RequestPinCode (/org/bluez/506/hci0/dev_A4_15_66_5B_B9_79)
    Enter PIN Code: 0000
    Release
    New device (/org/bluez/391/hci0/dev_A4_15_66_5B_B9_79)
    
    • refer to your headset documentation for the correct PIN (0000 shown above or 1234 is typical)
  3. Bluetooth audio configuration:
    • Make sure you have 'Source' and 'Media' enabled under [General] in /etc/bluetooth/audio.conf:
      # sed 's/#Disable=\(.*\)/Enable=Source,Sink,Headset,Gateway,Control,Socket,Media/' /etc/bluetooth/audio.conf -i # enable all modules
      
    • Restart the bluetooth daemon
  4. bluetooth-alsa configuration: Configure a 'btheadset' audio device:
    # cat <<EOT >/etc/asound.conf
    pcm.btheadset {
       type plug
       slave {
           pcm {
               type bluetooth
               device A4:15:66:5B:B9:79
               profile "auto"
           }  
       }  
       hint {
           show on
           description "BT Headset"
       }  
    }
    
    ctl.btheadset {
      type bluetooth
    }
    EOT
    
  5. You should now be able to play audio to the paired headset via ALSA:
    • For example with the aplay tool from the alsa-utils package:
      # aplay -D btheadset /usr/share/sounds/alsa/Front_Center.wav # play
      
    • or mplayer:
      # mplayer -ao alsa:device=btheadset /usr/share/sounds/alsa/Front_Center.wav
      
    • In order to get your headet's multimedia buttons (play,pause,next,previous) you need to create /etc/modules-load.d/uinput.conf containing uinput
    • For PulseAudio you need to have PulseAudio installed (pulseaudio-module-blueeooth) and have the PulseAudio sound server started: pulseaudio --start and do not need to have /etc/asound.conf configured

References:

Generic Access Protocol GAP

Protocol when devices are continuously advertising and there is no bonded connection. Example: temperature sensor advertising its value.

Two device roles:

  • Central - device such as Gateworks SBC
  • Peripheral - device such as a temperature sensor

Packets are 31 bytes.

Generic Attribute Profile GATT

Generic Attribute Profile (GATT) is used for Bluetooth Low Energy communication. This for a dedicated connection between two devices after GAP has already been completed. A BLE peripheral can only be connected to on central device at a time.

GATT has the following:

  • Client - A device who initates a GATT command or request. Ex: Gateworks SBC
  • Server - A device that receives GATT requests and then responds. Ex: Temperature Sensor
  • Characteristic - A data value, such as a battery voltage
  • Service - Collection of Characteristics
  • Descriptor - Additional information for a characteristic.
  • Identifiers - a UUID for services, descriptors, and characteristics.
  • Notifications - Client can be notified when a characteristic changes on a server. Avoids the need for the client to poll the server
  • Indication - The same as a notification, but the client must confirm to the server it received the message.

Using GATT with BlueZ 5.x with the gatttool:

  • Example: Controlling a MagicHue Bluetooth Smart Candle:
    root@bionic-newport:~# timeout 5s hcitool lescan
    LE Scan ...
    3C:A3:08:10:51:FE LEDBlue-081051FE 
    
    root@bionic-newport:~# gatttool -i hci0 -b 3C:A3:08:10:51:FE --primary
    attr handle = 0x0001, end grp handle = 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
    attr handle = 0x000c, end grp handle = 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
    attr handle = 0x0010, end grp handle = 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
    attr handle = 0x0023, end grp handle = 0x0033 uuid: 0000ffe5-0000-1000-8000-00805f9b34fb
    attr handle = 0x0034, end grp handle = 0x0044 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
    attr handle = 0x0045, end grp handle = 0xffff uuid: 0000fff0-0000-1000-8000-00805f9b34fb
    root@bionic-newport:~# gatttool -i hci0 -b 3C:A3:08:10:51:FE --characteristics
    handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
    handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
    handle = 0x0006, char properties = 0x0a, char value handle = 0x0007, uuid = 00002a02-0000-1000-8000-00805f9b34fb
    handle = 0x0008, char properties = 0x08, char value handle = 0x0009, uuid = 00002a03-0000-1000-8000-00805f9b34fb
    handle = 0x000a, char properties = 0x02, char value handle = 0x000b, uuid = 00002a04-0000-1000-8000-00805f9b34fb
    handle = 0x000d, char properties = 0x20, char value handle = 0x000e, uuid = 00002a05-0000-1000-8000-00805f9b34fb
    handle = 0x0011, char properties = 0x02, char value handle = 0x0012, uuid = 00002a23-0000-1000-8000-00805f9b34fb
    handle = 0x0013, char properties = 0x02, char value handle = 0x0014, uuid = 00002a24-0000-1000-8000-00805f9b34fb
    handle = 0x0015, char properties = 0x02, char value handle = 0x0016, uuid = 00002a25-0000-1000-8000-00805f9b34fb
    handle = 0x0017, char properties = 0x02, char value handle = 0x0018, uuid = 00002a26-0000-1000-8000-00805f9b34fb
    handle = 0x0019, char properties = 0x02, char value handle = 0x001a, uuid = 00002a27-0000-1000-8000-00805f9b34fb
    handle = 0x001b, char properties = 0x02, char value handle = 0x001c, uuid = 00002a28-0000-1000-8000-00805f9b34fb
    handle = 0x001d, char properties = 0x02, char value handle = 0x001e, uuid = 00002a29-0000-1000-8000-00805f9b34fb
    handle = 0x001f, char properties = 0x02, char value handle = 0x0020, uuid = 00002a2a-0000-1000-8000-00805f9b34fb
    handle = 0x0021, char properties = 0x02, char value handle = 0x0022, uuid = 00002a50-0000-1000-8000-00805f9b34fb
    handle = 0x0024, char properties = 0x0a, char value handle = 0x0025, uuid = 0000ffe6-0000-1000-8000-00805f9b34fb
    handle = 0x0027, char properties = 0x0a, char value handle = 0x0028, uuid = 0000ffe7-0000-1000-8000-00805f9b34fb
    handle = 0x002a, char properties = 0x0a, char value handle = 0x002b, uuid = 0000ffe8-0000-1000-8000-00805f9b34fb
    handle = 0x002d, char properties = 0x04, char value handle = 0x002e, uuid = 0000ffe9-0000-1000-8000-00805f9b34fb
    handle = 0x0030, char properties = 0x0a, char value handle = 0x0031, uuid = 0000ffea-0000-1000-8000-00805f9b34fb
    handle = 0x0035, char properties = 0x0a, char value handle = 0x0036, uuid = 0000ffe1-0000-1000-8000-00805f9b34fb
    handle = 0x0038, char properties = 0x02, char value handle = 0x0039, uuid = 0000ffe2-0000-1000-8000-00805f9b34fb
    handle = 0x003b, char properties = 0x08, char value handle = 0x003c, uuid = 0000ffe3-0000-1000-8000-00805f9b34fb
    handle = 0x003e, char properties = 0x10, char value handle = 0x003f, uuid = 0000ffe4-0000-1000-8000-00805f9b34fb
    handle = 0x0042, char properties = 0x02, char value handle = 0x0043, uuid = 0000ffeb-0000-1000-8000-00805f9b34fb
    handle = 0x0046, char properties = 0x0a, char value handle = 0x0047, uuid = 0000fff1-0000-1000-8000-00805f9b34fb
    handle = 0x0049, char properties = 0x02, char value handle = 0x004a, uuid = 0000fff2-0000-1000-8000-00805f9b34fb
    handle = 0x004c, char properties = 0x08, char value handle = 0x004d, uuid = 0000fff3-0000-1000-8000-00805f9b34fb
    handle = 0x004f, char properties = 0x10, char value handle = 0x0050, uuid = 0000fff4-0000-1000-8000-00805f9b34fb
    handle = 0x0053, char properties = 0x02, char value handle = 0x0054, uuid = 0000fff5-0000-1000-8000-00805f9b34fb
    root@bionic-newport:~# gatttool -i hci0 -b 3C:A3:08:10:51:FE --char-write-req -a 0x002e  -n 56ff000000f0aa # red
    Characteristic value was written successfully
    gatttool -i hci0 -b 3C:A3:08:10:51:FE --char-write-req -a 0x002e  -n 5600ff0000f0aa # green
    Characteristic value was written successfully
    gatttool -i hci0 -b 3C:A3:08:10:51:FE --char-write-req -a 0x002e  -n 560000ff00f0aa # blue
    Characteristic value was written successfully
    
  • The specific handle (denoting the GATT service and characteristic) and its values were determined by enabling HCI logging on an Android device while using the MagicHue Android app then viewing the log in Wireshark to see what values were being changed. This 'reverse engineering' technique is fairly common and widely described on the Internet.

Common Commandline Tools and Operations

Several command-line tools and operations are consistent among the various versions of the BlueZ stack.

Configuring Bluetooth Controller (hciconfig)

The hciconfig tool will allow you to identify and configure Bluetooth controllers. It is very similar to ifconfig in that it shows Bluetooth devices, their TX/RX bytes, MAC and some other relevant information. A Bluetooth device generally shows up as hciX where X is a zero-based number. That is, if there is only one Bluetooth adapter on your system, it would usually show up as hci0.

You can see the available Bluetooth controllers on a Linux system by looking in the /sys/class/bluetooth directory:

# ls /sys/class/bluetooth
hci0

Example uses:

  • show configuration for all controllers:
    # hciconfig
    hci0:   Type: BR/EDR  Bus: USB
            BD Address: 2C:3D:4F:04:12:55  ACL MTU: 339:6  SCO MTU: 180:1
            DOWN
            RX bytes:488 acl:0 sco:0 events:20 errors:0
            TX bytes:82 acl:0 sco:0 commands:20 errors:0
    
    • The above shows a single controller named 'hci0' with unique MAC of 2C:3D:4F:04:12:55 currently in the power down state
  • bring up controller (if you don't have a bluetooth daemon that automatically does this for you):
    hciconfig hci0 up
    
    • If this fails with an error like Operation not possible due to RF-kill then you need to unblock it via a hardware button/gpio or use the rfkill utility to unblock it:
      rfkill unblock all
      

The hciconfig command will show you the state of controllers as well (UP/DOWN, RUNNING, PSCAN, ISCAN). The Inquiry Scan (ISCAN) and Page Scan (PSCAN) settings determine device discover-ability (see discovery below).

UART based HCI configuration (hciattach)

The hciattach tool is used to attach serial devices via UART HCI to the BlueZ stack.

This is useful for on-board Bluetooth controllers that are connected directly to a processor UART. Gateworks does not use any such controllers.

Discoverability (hciconfig)

Every Bluetooth end-point device and controller has a unique MAC address (also known as a BDADDR) and a name.

A Bluetooth device needs to be in discovery mode to show up in a scan. Refer to the device documentation for details. Typically this involves holding a button down (often the power on button) for several seconds and results in a flashing blue LED indicating the device is in pairing or discovery mode.

The hciconfig command can be used to configure the discover-ability and the name of a bluetooth controller. A Bluetooth controller may start off in hidden mode and needs to be in the 'Inquiry Scan' state to be discoverable.

Examples:

  • show state of 'Inquiry Scan' and 'Page Scan':
    # hciconfig hci0
    
  • enable 'Inquiry Scan' state:
    # hciconfig hci0 iscan
    
  • enable 'Page Scan' state:
    # hciconfig hci0 pscan
    
  • enable both 'Page Scan' and 'Inquiry Scan' states:
    # hciconfig hci0 piscan
    
  • disable discovery mode (be hidden):
    # hciconfig hci0 noscan
    

The name that is shown with the MAC address of discovered nearby devices is configurable. For Linux Bluetooth controllers the name sub-command will configure the controllers name. You can also specify this in the Bluetooth daemon's configuration file.

Examples:

  • show the name of a controller:
    # hciconfig hci0 name
    hci0:   Type: BR/EDR  Bus: SDIO
            BD Address: 00:06:C6:FF:AD:1A  ACL MTU: 1021:7  SCO MTU: 120:6
            Name: 'ventana-0'
    
  • use the name instead of the device name:
    # hciconfig ventana-0
    hci0:   Type: BR/EDR  Bus: SDIO
            BD Address: 00:06:C6:FF:AD:1A  ACL MTU: 1021:7  SCO MTU: 120:6
            UP RUNNING PSCAN
            RX bytes:18030 acl:121 sco:0 events:910 errors:0
            TX bytes:7916 acl:76 sco:0 commands:448 errors:0
    
  • Set the name:
    # hciconfig hci0 name "MyUCI"
    # hciconfig hci0 name
    hci0:   Type: BR/EDR  Bus: SDIO
            BD Address: 00:06:C6:FF:AD:1A  ACL MTU: 1021:7  SCO MTU: 120:6
            Name: 'MyUCI'
    # hciconfig MyUCI
    hci0:   Type: BR/EDR  Bus: SDIO
            BD Address: 00:06:C6:FF:AD:1A  ACL MTU: 1021:7  SCO MTU: 120:6
            UP RUNNING PSCAN
            RX bytes:18393 acl:123 sco:0 events:917 errors:0
            TX bytes:8238 acl:79 sco:0 commands:450 errors:0
    
    

Scanning for Bluetooth devices available for pairing (hcitool)

The hcitool app from the bluez package can also be used to scan for and connect to Bluetooth devices in the area as well as give you information as to their identity (user defined name) and signal quality.

Examples:

  • Scan for nearby discoverable Bluetooth devices:
    # hciconfig hci0 up # make sure controller is powered on
    # hcitool -i hci0 scan # shows MAC and name of nearby devices which are configured as discoverable
    Scanning ..
            09:40:A4:45:B1:4B       P6
    
    • The above shows a single device found named 'P6' with a unique MAC address of '09:40:A4:45:B1:4B'
  • Connects to a specific Bluetooth device and show its link quality
    # hcitool cc 09:40:A4:45:B1:4B; hcitool lq 09:40:A4:45:B1:4B; hcitool con
    Link quality: 255
    Connections:
            < ACL 09:40:A4:45:B1:4B handle 256 state 7 lm MASTER
    # hcitool con
    Connections:
    #
    
    • The above connects to the device with the specified MAC address and shows the active connection link quality
  • To scan for Bluetooth Low Energy devices, use the following command:
    hcitool lescan
    

Pinging a device to test its connection (l2ping)

When a device has been discovered you can use l2ping from the bluez package to test the connection. This requires you to know the unique MAC address of the device:

# l2ping 09:40:a4:45:b1:4b
0 bytes from 09:40:a4:45:b1:4b id 0 time 9.12ms
0 bytes from 09:40:a4:45:b1:4b id 1 time 52.33ms
0 bytes from 09:40:a4:45:b1:4b id 2 time 22.50ms
0 bytes from 09:40:a4:45:b1:4b id 3 time 25.92ms
^C4 sent, 4 received, 0% loss
  • Use 'cntl-C' to stop the ping if you did not specify a -c parameter to limit the number of ping counts
  • You can ping a device even if it is no longer responding to scanning (because its no longer in discovery mode) as long as the device is powered on

Open A Connection (hcitool)

Use hcitool to open a connection between an HCI and a bluetooth device:

# hcitool cc 54:46:6B:01:7B:2B

Link Quality (hcitool)

Use hcitool to open a connection and determine hte link quality of a connection:

# hcitool cc 54:46:6B:01:7B:2B; hcitool lq 54:46:6B:01:7B:2B; hcitool con

#sdptool

Bluetooth Service Discovery Protocol (SDP) (sdptool)

The Bluetooth Service Discovery Protocol (SDP) provides a means by which service applications running on different Bluetooth enabled devices may discover each other's existence and exchange info to determine their characteristics.

Use sdptool from the bluez package to perform SDP queries on Bluetooth devices and for administering a local SDP daemon, or sdpd.

Example:

  • Show characteristics of the Sound Intone Bluetooth headset by showing all possible service records:
    # sdptool records 09:40:a4:45:b1:4b
    Service Name: JL_A2DP
    Service RecHandle: 0x10001
    Service Class ID List:
      "Audio Sink" (0x110b)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 25
      "AVDTP" (0x0019)
        uint16: 0x100
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Advanced Audio" (0x110d)
        Version: 0x0100
    
    Service RecHandle: 0x10002
    Service Class ID List:
      "AV Remote" (0x110e)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 23
      "AVCTP" (0x0017)
        uint16: 0x100
    Profile Descriptor List:
      "AV Remote" (0x110e)
        Version: 0x0100
    
    Service Name: JL_HFP
    Service RecHandle: 0x10003
    Service Class ID List:
      "Handsfree" (0x111e)
      "Generic Audio" (0x1203)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 4
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Handsfree" (0x111e)
        Version: 0x0105
    
    
  • Show records of a bluetooth keyboard:
    # sdptool records 54:46:6B:01:7B:2B
    Service Name: Broadcom Bluetooth Wireless  Keyboard                        
    Service Description: Keyboard
    Service Provider: Broadcom Corp.  
    Service RecHandle: 0x10000
    Service Class ID List:
      "Human Interface Device" (0x1124)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 17
      "HIDP" (0x0011)
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Human Interface Device" (0x1124)
        Version: 0x0100
    
    Service Name: Broadcom Bluetooth Wireless Keyboard PnP Server
    Service Description: Keyboard
    Service RecHandle: 0x10001
    Service Class ID List:
      "PnP Information" (0x1200)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 1
      "SDP" (0x0001)
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "PnP Information" (0x1200)
        Version: 0x0100
    
    
  • Show all devices advertising the A2DP Profile:
    # sdptool search A2DP
    Service Name: JL_A2DP
    Service RecHandle: 0x10001
    Service Class ID List:
      "Audio Sink" (0x110b)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
        PSM: 25
      "AVDTP" (0x0019)
        uint16: 0x100
    Language Base Attr List:
      code_ISO639: 0x656e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Advanced Audio" (0x110d)
        Version: 0x0100
    
    

Reference:

Pairing and bonding (Setting up connections)

Many of the bluetooth services can expose private data or allow control of a device, therefore for security reasons it is desired to securely pair devices in a fashion that doesn't make it too difficult to use conveniently.

Bluetooth uses a process called bonding where a bond is generated through a process called pairing. Pairing is triggered either by a specific request or triggered automatically when connecting to a service for the first time. There is usually some form of user interaction to confirm the identify of the devices but once pairing is complete a bond will have been formed between the two devices, enabling them to connect to each other in the future without requiring the pairing process again. If desired the bonding relationship can later be removed by the user which would force a pairing to be completed again.

You can also tell your controller to specifically trust a device based on its MAC address which eliminates the need for pairing. It is the controller that decides to pair or trust a device, not the device itself.

The configuration for paired devices is stored in /var/lib/bluetooth/<hci_mac>/.

The method used for pairing a controller to a device differs depending on the version of the BlueZ stack being used:

  • BlueZ 5:
    • The BlueZ 5 bluetooth daemon stores its persistent pairing details in /var/lib/bluetooth/<hci_MAC>/<device_MAC>/info with the format of:
      [LinkKey]
      Key       String  <key in hex format>
      Type      Integer <Type of link key>
      PINLength Integer <Length of PIN>
      
      • therefore you can remove all pairing history by removing that file and restarting bluetoothd
    • You can request pairing with devices using the bluetoothctl CLI pair <bdaddr> command:
      # bluetoothctl
      [NEW] Controller 00:15:83:6B:E2:BD BlueZ 5.37 [default]
      [bluetooth]# power on
      Changing power on succeeded
      [bluetooth]# scan on
      Discovery started
      [CHG] Controller 00:15:83:6B:E2:BD Discovering: yes
      [NEW] Device 54:46:6B:01:7B:2B 54-46-6B-01-7B-2B
      [CHG] Device 54:46:6B:01:7B:2B RSSI: -75
      [CHG] Device 54:46:6B:01:7B:2B LegacyPairing: no
      [CHG] Device 54:46:6B:01:7B:2B Name: Bluetooth FAVI
      [CHG] Device 54:46:6B:01:7B:2B Alias: Bluetooth FAVI
      [bluetooth]# pair 54:46:6B:01:7B:2B
      Attempting to pair with 54:46:6B:01:7B:2B
      [CHG] Device 54:46:6B:01:7B:2B Connected: yes
      [CHG] Device 54:46:6B:01:7B:2B Modalias: usb:v0A5Cp8502d011B
      [CHG] Device 54:46:6B:01:7B:2B UUIDs: 00001000-0000-1000-8000-00805f9b34fb
      [CHG] Device 54:46:6B:01:7B:2B UUIDs: 00001124-0000-1000-8000-00805f9b34fb
      [CHG] Device 54:46:6B:01:7B:2B UUIDs: 00001200-0000-1000-8000-00805f9b34fb
      [CHG] Device 54:46:6B:01:7B:2B Paired: yes
      Pairing successful
      [CHG] Device 54:46:6B:01:7B:2B Connected: no
      [CHG] Device 54:46:6B:01:7B:2B LegacyPairing: yes
      [CHG] Device 54:46:6B:01:7B:2B RSSI: -66
      [CHG] Device 54:46:6B:01:7B:2B RSSI: -66
      [bluetooth]# scan off
      [CHG] Controller 00:15:83:6B:E2:BD Discovering: no
      Discovery stopped
      [bluetooth]# paired-devices
      Device 54:46:6B:01:7B:2B Bluetooth FAVI
      Device 09:40:A4:45:B1:4B P6
      [bluetooth]#
      
      • above first we enable scanning, then we pair with a device, next we disable scanning (optional), and lastly we show paired devices
    • You can respond to pairing requests using the bluetoothd internal agent using the bluetoothctl CLI:
      # bluetoothctl
      [NEW] Controller 00:15:83:6B:E2:BD BlueZ 5.37 [default]
      [bluetooth]# power on
      Changing power on succeeded
      [bluetooth]# agent on
      Agent registered
      [bluetooth]# default-agent
      Default agent request successful
      [NEW] Device 00:15:83:3D:0A:57 yocto18-0
      Request PIN code
      [agent] Enter PIN code: 0000
      [CHG] Device 00:15:83:3D:0A:57 Paired: yes
      [CHG] Device 00:15:83:3D:0A:57 Connected: no
      [bluetooth]# paired-devices
      Device 00:15:83:3D:0A:57 yocto18-0
      
      • above we first enable the agent, then set it to the default agent and wait for pairing requests. A pairing request comes from a device with a bdaddr or 00:15:83:3D:0A:57 and a name of yocto18-0 and we enter in the PIN that the device is expecting and we pair with it
  • BlueZ 4:
    • The BlueZ 4.x bluetooth daemon stores persistent pairing details /var/lib/bluetooth/<hci_MAC>/linkkeys with the following format:
      <bdaddr> <128bit_link_key> <key_type> <key_length>
      
      • therefore you can remove all pairing history by removing that file and restarting bluetoothd
    • You can pair with a device using the python 'simple-agent' found in the bluez4 git tree here (requires python, python-dbus and python-gobject)
      # ./simple-agent hci0 54:46:6B:01:7B:2B
      RequestPinCode (/org/bluez/449/hci0/dev_54_46_6B_01_7B_2B)
      Enter PIN Code: 1234
      Release
      New device (/org/bluez/449/hci0/dev_54_46_6B_01_7B_2B)
      # ls /var/lib/bluetooth/00\:15\:83\:3D\:0A\:57/
      classes   did       linkkeys  profiles  
      config    lastused  names     sdp       
      # cat /var/lib/bluetooth/00\:15\:83\:3D\:0A\:57/linkkeys 
      54:46:6B:01:7B:2B E45EED6C956306606A306EA1A2E22B68 0 4
      
      • Depending on the version of python you have installed, you may need to patch simple-agent with the following changes:
        --- simple-agent.orig
        +++ simple-agent
        @@ -2,8 +2,7 @@
         
         from __future__ import absolute_import, print_function, unicode_literals
         
        -from gi.repository import GObject
        -
        +import gobject
         import sys
         import dbus
         import dbus.service
        @@ -122,7 +121,7 @@
                path = "/test/agent"
                agent = Agent(bus, path)
         
        -       mainloop = GObject.MainLoop()
        +       mainloop = gobject.MainLoop()
         
                if len(args) > 1:
                        if len(args) > 2:
        
    • Alternatively you can also pair using the compiled agent.c found in the bluez4 git tree here
      # bluetoothd
      # ./agent 1234 54:46:6B:01:7B:2B
      Pincode request for device /org/bluez/2039/hci0/dev_54_46_6B_01_7B_2B
      Agent has been released
      
    • if this exist without the 'Agent has been released' message then pairing was unsuccessful
    • this can be cross-compiled with the following (ie Yocto SDK):
      $CC -DVERSION=4.101 $(pkg-config --cflags dbus-1) agent.c $(pkg-config --libs dbus-1) -o agent
      
    • For examples on how to pair using dbus messages see the simple-agent and agent.c source code
  • BlueZ 3:
  • The BlueZ 3.x bluetooth daemon stores persistent pairing details in /var/lib/bluetooth/<hci_MAC>/pincodes in the form of:
    <mac> <pin>
    
    • therefore you can remove all pairing history by removing that file and restarting bluetoothd
    • If you manually edit this file, you will need to restart the hcid bluetooth daemon:
      # echo "00:02:72:C9:56:47 0000" >> /var/lib/bluetooth/00\:15\:83\:3D\:0A\:57/pincodes
      # /etc/init.d/bluez-utils restart
      

References:

Bluetooth Controller Hardware

Gateworks has used and tested the following USB based controllers.

USB based (btusb)

Their is a large variety of USB based Bluetooth controllers supported by the btusb kernel driver. Here are some common ones that Gateworks has tested:

GW17039 (DHXA-335D)

The Unex DHXA-335D is a PCIe half-mini card using Atheros WB222/AR9565 available on Gateworks store. Some of it's features include:

  • Wifi: 802.11b,802.11g,802.11n, Bluetooth v4.0
    • MIMO: 1x1(1-stream)
    • Spectral Band 2.400~2.497
    • Channel Spacing: Wifi 5MHz, BT 1MHz
    • Output power: 18dB Wifi, 2dBm BT
  • Other Specifications:
    • Connectors: 2x U.FL
    • Dimensions: 26.8mm x 29.85mm
    • ath9k driver support
    • Operation temprature: -10C,+60C ambient
    • RoHS

DHXA-225 (EOL)

The Unex DHXA-225 is a MiniPCIe form-factor combo card using Atheros WB225/AR9485+AR3012 providing:

  • 802.11bgn 1x1 MIMO wifi (PCIe device supported by the linux ath9k driver)
    • For OpenWrt this is provided by the kmod-ath9k kernel module package and is built into our default root filesystems by default
  • Bluetooth 4.0 HCI (USB device supported by the linux ath3k driver)

Writing code supporting Bluetooth

If you wish to or need to write your own applications to support Bluetooth there are a variety of great resources out there on the Internet:

iBeacon

iBeacon is a form of BLE that was created by Apple to provide location based information and services to iPhones.

For example, someone is walking around with an iPhone with a specific app loaded that is listening for these iBeacons. The app on the phone will respond when the iBeacon comes in range. (retail environment, sale special)

Note: See TracWiki for help on using the wiki.