Bluetooth Implementation

Initialization

Initialize the Bluetooth subsystem using bt_init(). Caller shall be either task or a fiber. Caller must ensure that function succeeds by checking return code for errors.

APIs

The following Bluetooth APIs are provided:

bt_enable()
Enables the Bluetooth subsystem.
bt_le_adv_start()
Sets up advertisement, scans for data, and starts advertising.

Bluetooth Application Example

A simple Bluetooth beacon application is shown below. The application initializes a Bluetooth Subsystem and enables non-connectable advertising. It acts 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
65
66
67
68
69
70
#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_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_PARAM(BT_LE_ADV_SCAN_IND,
					      BT_LE_ADV_ADDR_NRPA,
					      BT_GAP_ADV_FAST_INT_MIN_2,
					      BT_GAP_ADV_FAST_INT_MAX_2),
			      ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
	if (err) {
		printk("Advertising failed to start (err %d)\n", err);
		return;
	}

	printk("Beacon started\n");
}

#ifdef CONFIG_MICROKERNEL
void mainloop(void)
#else
void main(void)
#endif
{
	int err;

	/* Initialize the Bluetooth Subsystem */
	err = bt_enable(bt_ready);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
	}
}

Testing with QEMU

A Bluetooth application might be tested with QEMU. In order to do so, a Bluetooth controller needs to be connected to the emulator.

Using Host System Bluetooth Controller in QEMU

The host system’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 the Makefile.

On the Host side, BlueZ allows to “connect” Bluetooth controller through a so-called user channel.

  1. Use the btproxy tool to open the listening UNIX socket, type:

    $ sudo tools/btproxy -u
    Listening on /tmp/bt-server-bredr
    

    Note

    Ensure that the Bluetooth controller is down before using the btproxy command.

  2. To run Bluetooth application in the QEMU, go to application folder and type:

    $ make qemu
    

    Note

    Bluetooth sample applications are located in samples/bluetooth folder.

Running QEMU now results in a connection with the second serial line to bt-server-bredr UNIX socket. Now, an application can use the Bluetooth device.