Bluetooth serial client using Windows socket API


This post shows how you can discover paired Bluetooth devices, and communicate with them, using Windows socket API. The Windows socket API is available in .NET through the excellent 32feet.NET library.

This is how you can discover Bluetooth devices paired with Windows

client = new BluetoothClient();
devices = client.DiscoverDevices(10, true, true, false);

This is how you can connect with a device, and obtain a NetworkStream to read from

Guid MyServiceUuid = new Guid("{00001101-0000-1000-8000-00805F9B34FB}");
client.Connect(devices[0].DeviceAddress, MyServiceUuid);
NetworkStream stream = client.GetStream();
ReadAsync(stream);

Here’s the implementation of ReadAsync

byte[] buffer = new byte[100];
while (true)
{
    try
    {
        int length = await stream.ReadAsync(buffer, 0, buffer.Length);
        // do something with buffer
    }
    catch
    {
        break;
    }
}

The application can send data at any time as follows

stream.Write(buffer, 0, buffer.Length);

The code above is available at GitHub as part of the Bluetooth Serial Client Tool.

bluetooth-serial-client-tool.PNG

Bluetooth serial server using Windows socket API


This post describes a means to simulate a Bluetooth serial device on Windows. This can be useful to test Bluetooth applications running on Android and Windows, that use a virtual serial port to communicate with devices.

Windows Bluetooth socket API can be used to create a server (listener). I use 32feet.NET here, a neat .NET library layered over the C/C++ socket APIs provided by Microsoft.

Here’s how you can create a Bluetooth listener on the primary adapter/radio

Guid MyServiceUuid = new Guid("{00001101-0000-1000-8000-00805F9B34FB}");
BluetoothListener listener = new BluetoothListener(MyServiceUuid); // Listen on primary radio
listener.Start();
listener.BeginAcceptBluetoothClient(acceptBluetoothClient, null);

The acceptBluetoothClient callback will be called when a client connects, and may be implemented as follows

if (listener == null) return;
client = listener.EndAcceptBluetoothClient(ar);
stream = client.GetStream();
ReadAsync(stream);

ReadAsync is an async method that continuously receives data over the Bluetooth socket, and does something useful with it

byte[] buffer = new byte[100];
while (true)
{
    try
    {
        int length = await stream.ReadAsync(buffer, 0, buffer.Length);
        // do something useful with data in buffer
    }
    catch
    {
        break;
    }
}

The application can send data at any time as follows

stream.WriteAsync(buffer, 0, buffer.Length);

As a bonus to the reader who’s come this far, the code above is available at GitHub as part of the Bluetooth Serial Server Tool.

bluetooth-spp-tool.PNG

Getting Started with Bluetooth Low Energy by Kevin Townsend et al; O’Reilly Media


Getting Started with Bluetooth Low Energy, Tools and Techniques for Low-Power Networking

Bluetooth LE, or Bluetooth Smart as it is officially known, has generated a lot of interest for all the good reasons. Getting Started with Bluetooth Low Energy by Kevin Townsend et al is a solid guide to the topic, along with other good books such as Bluetooth Low Energy: The Developer’s Handbook.

The book begins by discussing the key characteristics, limitations, and use cases of Bluetooth LE technology, in chapter 1. The following four chapters take a deep dive into the protocols that comprise Bluetooth LE, beginning with an overview in Chapter 2. Chapter 3 delves into the Generic Attribute Profile or GAP (advertising and connections). Chapter 4 delves into Generic Attribute Profile or GATT (services and characteristics).

Makers need to select hardware to leverage Bluetooth LE. It may come in the form of a module that you program to act as a peripheral, or a USB dongle that you may plug into a USB host. Chapter 5 discusses several such options. Chapters 6 and 7 delve into debugging and design tools that aid developers during development and troubleshooting.

Chapter 8 shows how to leverage Bluetooth LE on Android using the Bluetooth Application Accelerator library from the Bluetooth SIG. You’ll learn how to establish connection and communicate with a remote device. Chapter 9 delves into Bluetooth LE programming on iOS by demonstrating several practical applications.

Chapter 10, the concluding chapter, shows how to leverage Bluetooth LE on embedded devices. It uses a hardware module introduced in chapter 5, in conjunction with ARM’s mbed platform, to build a peripheral that can be used with Android and iOS devices.

All source code shown in the book can be forked from the author’s GitHub repo. The text has occasional spelling mistakes that don’t affect readability.

I’d like to thank O’Reilly Media for providing an e-book for review.

Bluetooth on Raspberry Pi with Buildroot


This post shows how to build Bluetooth support with Buildroot for a Raspberry Pi. You’ll need a Bluetooth adapter such as the Bluetooth 4.0 USB Module from Adafruit. That adapter is also Bluetooth Smart (LE) ready.

I recommend using Buildroot 2014.08 because bluez-tools such as bt-adapter and bt-agent work with its version of Bluez.

Kernel Configuration

Enable Bluetooth subsystem support under Networking support

Bluetooth subsystem support

Enable RFCOMM  protocol support under Bluetooth subsystem support, if you want Bluetooth SPP support. Enable BNEP protocol support, if you want support for networking over Bluetooth. Enable HIDP protocol support, if you want support for Bluetooth enabled keyboard and mice.

RFCOMM and BNEP support

Since we’re using a USB adapter, enable HCI USB driver under Bluetooth subsystem support, Bluetooth device drivers

HCI USB driver

Buildroot Packages

The Kernel Bluetooth stack is called BlueZ. BlueZ also provides a set of utilities that can be used from the command line. To add those, select bluez-utils under Target packages, Networking applications

bluez-utils

If using Buildroot 2014.08, select bluez-utils 5.x package instead

bluez5_utils

make the Linux system and copy to SD card.

Useful commands

Look for interfaces

hciconfig -a

Bring up HCI interface

hciconfig hci0 up

Make the device discoverable

hciconfig hci0 piscan

Scan available devices

hcitool scan

Ping a device

l2ping C8:3E:99:C6:1B:F8

Browse capabilities of a device

sdptool browse C8:3E:99:C6:1B:F8

Run bluetooth daemon

bluetoothd

If using Buildroot 2014.08

/usr/libexec/bluetooth/bluetoothd &

Browse local capabilities

sdptool browse local

Another means to discover available devices, using bluez-tools

bt-adapter -d

Connect and pair with a device listed by the command above

bt-device -c 5C:0E:8B:03:6E:4E

Create a network connection and obtain IP address

bt-network -c C8:3E:99:C6:1B:F8 nap
sudo dhclient bnep0

Create a serial port

sdptool add --channel=7 SP
rfcomm connect /dev/rfcomm0 C8:3E:99:C6:1B:F8 7

Use screen with the above serial port

screen /dev/rfcomm0 115200

Bluetooth LE commands

Scan for Bluetooth LE devices

hcitool lescan

Access services and characteristics provided by an LE peripheral

gatttool -b 7F:AE:48:2B:00:0C -t random -I

gatttool prompt supports a set of commands to interact with the peripheral

connect
primary
char-desc
char-read-hnd handle
char-write-req handle data

Enable advertising as an iBeacon

hciconfig hci0 leadv
hciconfig hci0 noscan
hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00

Bluetooth is big. Go ahead and do something with it.

Customize Buildroot to build bluez-tools


I am building Bluetooth support into my custom embedded Linux system with Buildroot, but couldn’t find basic command line tools that work with newer versions of BlueZ. That is when I came across bluez-tools, a GSoC project that is able to fill the gap.

To build bluez-tools requires adding my own package to Buildroot. What follows is a brief description of how to do that.

Download source code of bluez-tools. I did this outside of the buildroot folder, by cloning from the author’s GitHub repo

git clone https://github.com/khvzak/bluez-tools.git

Add an override rule to file local.mk, in the root folder of buildroot. That tells buildroot not to download package source from the internet, but to copy the source from the folder created above

BLUEZ_TOOLS_OVERRIDE_SRCDIR = /home/parallels/github/bluez-tools/

Create a folder for bluez-tools package

mkdir package/bluez-tools

Create package/bluez-tools/bluez-tools.mk file for the package with

################################################################################
#
# bluez-tools
#
################################################################################

BLUEZ_TOOLS_DEPENDENCIES = dbus libglib2 readline
BLUEZ_TOOLS_AUTORECONF = YES

$(eval $(autotools-package))

BLUEZ_TOOLS_AUTORECONF tells buildroot to generate configure script and Makefile.in by invoking autoconf et al.

Create configuration file package/bluez-tools/Config.in for the package with

config BR2_PACKAGE_BLUEZ_TOOLS
	bool "bluez-tools"
	help
	  This is a GSoC'10 project to implement a new command line tools for bluez (bluetooth stack for linux). The project implemented in C and uses the D-Bus interface of bluez. 

	  https://code.google.com/p/bluez-tools/

Add the package to package/Config.in

source "package/bluez-tools/Config.in"

Enter configuration menu and select the package

make menuconfig

bluez-tools

Note that bluez-tools package is under Networking applications because I added it to menu “Networking applications” in package/Config.in

Invoke make to perform the build

make

If you get any build errors try

make clean
make

make clean will delete Linux kernel config. Either save the config, or do it all over again.

With Buildroot 2015.05, a command such as

bt-adapter -l

Fails with

bt-adapter: bluez service is not found
Did you forget to run bluetoothd?

bluetoothd is running just fine. Got to figure that one out.

It works all right with Buildroot 2014.08, but have noted the following issue with bt-device

# bt-device -c 5C:0E:8B:03:6E:4E
Connecting to: 5C:0E:8B:03:6E:4E
Device: CS3070:10172522500886 (5C:0E:8B:03:6E:4E)
Enter passkey: 1234
Segmentation fault

Debugging with gdb reveals the following backtrace

#0  0xb6e77d00 in g_utf8_validate () from /usr/lib/libglib-2.0.so.0
#1  0xb6e7b5c8 in g_variant_new_string () from /usr/lib/libglib-2.0.so.0
#2  0x0000c0b8 in _bt_agent_method_call_func (connection=<optimized out>,
    sender=<optimized out>, object_path=<optimized out>,
    interface_name=<optimized out>, method_name=0x18fc228 "RequestPinCode",
    parameters=0x1905f00, invocation=0x18fdab0, user_data=0x0)
    at lib/agent-helper.c:310

Analyzing lib/agent-helper.c indicates a possible cause, passkey is being read into an uninitialized gchar pointer

            g_print("Enter passkey: ");
            errno = 0;
            if (scanf("%s", &ret) == EOF && errno)
                g_warning("%s\n", strerror(errno));
            g_dbus_method_invocation_return_value(invocation, g_variant_new_string(ret));

Should not be hard to fix.

bt-network crashes when used thus

bt-network -c C8:3E:99:C6:1B:F8 panu

Backtrace with gdb appears thus

#0  0xb6ec7ec8 in g_bit_lock () from /usr/lib/libglib-2.0.so.0
#1  0xb6f240a0 in g_variant_n_children () from /usr/lib/libglib-2.0.so.0
#2  0xb6f24100 in g_variant_get_child_value () from /usr/lib/libglib-2.0.so.0
#3  0x000192e8 in network_connect (self=self@entry=0x14d3470, 
    uuid=0xbef76e9e "panu", error=error@entry=0xbef76be4)
    at lib/bluez/network.c:178
#4  0x0000a3bc in main (argc=0, argv=0x14e5128) at bt-network.c:186

Analyzing the source code reveals another possible bug

        GVariant *proxy_ret = g_dbus_proxy_call_sync(self->priv->proxy, "Connect", g_variant_new ("(s)", uuid), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
        if (proxy_ret != NULL)
                return NULL;
        proxy_ret = g_variant_get_child_value(proxy_ret, 0);