Developing Bluetooth Applications
Initialization
The Bluetooth subsystem is initialized using the bt_init()
function. The caller shall be either a task or a fiber. The caller
should ensure that function succeeds by checking the return code for
errors. If a function pointer is passed to bt_init()
the
initialization happens synchronously and the completion is notified
through the given function.
Bluetooth Application Example
A simple Bluetooth beacon application is shown below. The application initializes the Bluetooth Subsystem and enables non-connectable advertising, effectively acting as a Bluetooth Low Energy broadcaster.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include <stdint.h>
#include <stddef.h>
#include <misc/printk.h>
#include <misc/util.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#define DEVICE_NAME "Test beacon"
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
/*
* Set Advertisement data. Based on the Eddystone specification:
* https://github.com/google/eddystone/blob/master/protocol-specification.md
* https://github.com/google/eddystone/tree/master/eddystone-url
*/
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),
BT_DATA_BYTES(BT_DATA_SVC_DATA16,
0xaa, 0xfe, /* Eddystone UUID */
0x10, /* Eddystone-URL frame type */
0x00, /* Calibrated Tx power at 0m */
0x00, /* URL Scheme Prefix http://www. */
'z', 'e', 'p', 'h', 'y', 'r',
'p', 'r', 'o', 'j', 'e', 'c', 't',
0x08) /* .org */
};
/* Set Scan Response data */
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static void bt_ready(int err)
{
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
/* Start advertising */
err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad),
sd, ARRAY_SIZE(sd));
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
printk("Beacon started\n");
}
void main(void)
{
int err;
/* Initialize the Bluetooth Subsystem */
err = bt_enable(bt_ready);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
}
}
|
The key APIs employed by the beacon sample are bt_enable()
that’s used to initialize Bluetooth and then bt_le_adv_start()
that’s used to start advertising a specific combination of advertising
and scan response data.
Testing with QEMU
It’s possible to test Bluetooth applications using QEMU. In order to do so, a Bluetooth controller needs to be exported from the host OS (Linux) to the emulator.
Using Host System Bluetooth Controller in QEMU
The host OS’s Bluetooth controller is connected to the second QEMU
serial line using a UNIX socket. This socket employs the QEMU option
-serial unix:/tmp/bt-server-bredr
. This option is already
added to QEMU through QEMU_EXTRA_FLAGS in most Bluetooth
sample Makefiles’ and made available through the ‘qemu’ make target.
On the host side, BlueZ allows to export its Bluetooth controller through a so-called user channel for QEMU to use:
Make sure that the Bluetooth controller is down
Use the btproxy tool to open the listening UNIX socket, type:
$ sudo tools/btproxy -u Listening on /tmp/bt-server-bredr
Choose one of the Bluetooth sample applications located in
samples/bluetooth
.To run Bluetooth application in QEMU, type:
$ make qemu
Running QEMU now results in a connection with the second serial line to
the bt-server-bredr
UNIX socket, letting the application
access the Bluetooth controller.