Bluez: Advertise Service/Gatt Server Example

Bluez: advertise service / gatt server example?

Eventually, I discovered the answers to all the questions I had.

I will start by answering the last question:

The commands I use only set-up the BLE device to advertise some data, but iOS reports that the connection is accepted. What part of bluez is accepting incoming connections?

This one was answered on the bluez mailing-list, in response to me.

Summary: the BLE connection is accepted at the HCI level by the kernel. If you want to use that connection from user space you need to use an l2cap socket with the ATT channel ID (which is 4).

Bleno has a good example of using an L2CAP socket.

How an L2CAP socket works is basically like this:

/* create L2CAP socket, and bind it to the local adapter */
l2cap_socket = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);

hci_device_id = hci_get_route(NULL);
hci_socket = hci_open_dev(hci_device_id);
memset(&l2cap_address, sizeof(l2cap_address));
l2cap_address.l2_family = AF_BLUETOOTH;
l2cap_address.l2_bdaddr = hci_device_address;
l2cap_address.l2_cid = htobs(ATT_CID);

bind(l2cap_socket, (struct sockaddr*)&l2cap_address, sizeof(l2cap_address));
listen(l2cap_socket, 1);

while (1) {
/* now select and accept() client connections. */
select(l2cap_socket + 1, &afds, NULL, NULL, &tv);
client_socket = accept(l2cap_socket, (struct sockaddr *)&l2cap_address, &len);

/* you can now read() what the client sends you */
int ret = read(client_socket, buffer, sizeof(buffer));
printf("data len: %d\n", ret);
for (i = 0; i < ret; i++) {
printf("%02x", ((int)buffer[i]) & 0xff);
}
printf("\n");
close(client_socket);
}

How to advertise a service?

I realized I needed an answer to the previous question to answer that one.

Once you can read the data over L2CAP socket, everything makes more sense, for example, if your Android phone does gatt.discoverServices(), then the little program above will read (i.e. receive):

10 0100 ffff 0028

Which basically means:

10: READ_BY_GROUP
0100: from handle 0001
ffff: to handle ffff
0028: with UUID 2800

This request is the way any BLE peripheral will request the list of services.

Then, you can answer this request with the list of services your device provides, formatted according to the GATT protocol.

Again, see the implementation of this in Bleno.

BlueZ example gatt server

The battery level example uses the Bluetooth service adopted UUID (0x180F) and attribute format (Please see this). As such, when the mobile phone app finds the service and sees the UUID, it will know that this is the battery service, and add the % when reading the value. This is a major advantage when using adopted services/characteristics vs custom ones, you can add intelligence at the remote end because the local end has a predefined format. Please note that this also applies to adopted heart rate service/characteristic (the app will immediately add bpm), adopted temperature service/characteristic (the app will immediately add (°C), and so on.

For a full list of adopted services and characteristics, please see these links:-

  • Adopted GATT Services
  • Adopted GATT Characteristics

For further reading about this subject:-

  • Bluetooth GATT: How to Design Custom Services and Characteristics

I hope this helps.

BlueZ: How to set up a GATT server from the command line

So this is now handled with the new bluetoothctl tool. A gatt table can be set up using this tool as follows:-

#bluetoothctl
[bluetoothctl] menu gatt
[bluetoothctl] register-service 0xFFFF # (Choose yes when asked if primary service)
[bluetoothctl] register-characteristic 0xAAAA read # (Select a value of 1 when prompted)
[bluetoothctl] register-characteristic 0xBBBB read,write # (Select a value of 0 when prompted)
[bluetoothctl] register-characteristic 0xCCCC read # (Select a value of 2 when prompted)
[bluetoothctl] register-application # (This commits the services/characteristics and registers the profile)
[bluetoothctl] back
[bluetoothctl] advertise on

I've tried this with a few service/characteristic combinations and was able to get it to work. The GAP (0x1800) and GATT (0x1801) services are available by default and will be part of the GATT table when you advertise. You can also use the following command to see the available services:-

[bluetoothctl] show
Controller 00:AA:BB:CC:DD:EE (public)
Name: MyMachine
Alias: MyMachine
Class: 0x000c0000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Headset AG (00001112-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
**UUID: Unknown (0000ffff-0000-1000-8000-00805f9b34fb)**
UUID: Headset (00001108-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no

Writing Gatt Server Application in Bluez

bluez gatt dbus apis are now complete as of version 5.29. You may consider using those if going via the dbus rather than directly through library calls is acceptable for you.

Setup BlueZ GATT Server with random address?

I think I was having a similar problem. Here's how I solved my problem:

After a lot of searching, I found that PyBluez just uses gattlib for all ble stuff: documentation

I was able to connect to my device with the following: (python 2.7)

import gattlib
requester = gattlib.GATTRequester('EF:76:B5:CC:36:A0', False)
reqer.connect(True, channel_type='random')

I know it's not the same as your problem, but I'm hoping it might help anyways.

Bluetooth Low Energy in C - using Bluez to create a GATT server

I got the example GATT server running for BlueZ 5.31 (latest as of this post):

My environment:

Vagrant

Virtual Box

Ubuntu Trusty Tahr as a guest OS (v. 14.04 32-bit OS)

Updated to linux kernel 3.19

Installed packages:

* libglib2.0-dev

* libdbus-1-dev

* libudev-dev

* libical-dev

* libreadline-dev

Downloaded BlueZ 5.31 from here: https://www.kernel.org/pub/linux/bluetooth/bluez-5.31.tar.xz

Installation of updated kernel (v. 3.19):

sudo apt-get update

sudo apt-get install --install-recommends linux-generic-lts-vivid

A reboot is necessary. I'm using Vagrant and lost shared folder access. If this happens to you, wait for vagrant to report the error and go into the VM anyway (vagrant ssh). In the VM, issue this command to fix the shared folder problem:

sudo /etc/init.d/vboxadd setup

I would reboot again (probably not necessary), to check that the shared folder is active again.

Once back in the VM, continue the installation of BlueZ 5.31:

cd ~

sudo apt-get install libglib2.0-dev libdbus-1-dev libudev-dev libical-dev libreadline-dev

wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.31.tar.xz

tar xvf bluez-5.31.tar.xz

cd bluez-5.31

./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var --disable-systemd --enable-experimental --enable-maintainer-mode

make

sudo make install

sudo cp attrib/gatttool /usr/bin

Installation completed. Check it as follows:

hciconfig
You should get the follow response (or something similar):

hci0: Type: BR/EDR Bus: USB

BD Address: 00:1A:7D:DA:71:0C ACL MTU: 310:10 SCO MTU: 64:8

DOWN

RX bytes:15528 acl:126 sco:0 events:683 errors:0

TX bytes:6459 acl:146 sco:0 commands:234 errors:0

Configure the Bluetooth adapter, start advertising, start example GATT server (heart rate service) with verbose on (my adapter is hci0):

cd BlueZ 5.31 directory
sudo tools/btmgmt -i hci0 power off

sudo tools/btmgmt -i hci0 le on

sudo tools/btmgmt -i hci0 connectable on

sudo tools/btmgmt -i hci0 name "some friendly name"

sudo tools/btmgmt -i hci0 advertising on

sudo tools/btmgmt -i hci0 power on

tools/btgatt-server -i hci0 -s low -t public -r -v

Go to another device (I've used an iPod, an Android -- Samsung Galaxy 5S and Nexus tablet -- and another PC running BlueZ) and connect to the service. Here is how I did it on another PC running BlueZ:

gatttool -b MAC address of GATT server -I

connect

primary

characteristics

You can issue other commands to read and write to the GATT server.

I've also created a custom GATT server (your original request) by copying and editing this file: tools/btgatt-server.c. You can edit the Makefile.tools file to include your custom server in the build. You'll have to run automake, make, and sudo make install to get it running.



Related Topics



Leave a reply



Submit