A simple GATT Server, part 1

Article

TJ Dahunsi

Sep 05 2014 · 5 mins

Categories:
technology

In the last post I discussed the two device roles ins BLE communication. Let's dive into the latter role, the Server, for a bit.

We know the server keeps that data available to it in a nested structure composed of GATT profiles, services and characteristics, where the characteristics are the items that actually hold data. To communicate with the GATT Client, these characteristics support 4 actions:

  1. Write

  2. Read

  3. Notifications

  4. Indications

These 4 methods are used to transfer data. The first method, write, is used to send data from the Client to the server. The remaining 3 are used to get data from the Server to the Client. I'll clarify these below.

Read commands are fairly simple. The client simply requests to "read" a characteristic with a particular UUID, and the data is sent to the client as bytes. At any one time, the Server can only send packets that are limited to 22 bytes in length which is longer than the remaining methods; those are limited to 20 bytes.

Write commands are used to write bytes to a characteristic from the Client.

Notifications are unacknowledged packets of data that will continually send out data as long that there is a client that is subscribed to them. Again, the packets of data are unacknowledged so if a particular notification packet is not transferred successfully, there is no flag. The next notification is just fired as scheduled. In the examples I demonstrate, this is what I'' be using.

Indications, like notifications require the client to be subscribed to them. However, each packet is acknowledged increasing reliability at the expense of speed.

My choice of hardware for BLE communication is the BLE112 by Bluegiga. For more in depth information and extremely thorough documentation of the BLE API to expand your BLE project, you should sign up for their support. It is free, and it is amazing. You will also find their forums to be extremely useful. When I first started out using BLE I trawled it significantly, and almost all the questions I had were already asked. The one's that weren't, I asked and I got speedy responses within the day. They are to class, top quality guys there.

Now that we know characteristics support methods to send and receive data, how do we set up the characteristics to do so? For Bluegiga's BLE112, this is very conveniently done using XML. Available from Bluegiga when you sign up is a software development kit (SDK) that allows you flash the firmware used on the BLE112. I'm going to share here the GATT profile structure used for my project.

<?xml version="1.0" encoding="UTF-8" ?> <configuration> <!-- 1800: org.bluetooth.service.generic\_access --> <service uuid="1800" id="generic\_access"> <description>Generic Access</description> <!-- 2A00: org.bluetooth.characteristic.gap.device\_name --> <characteristic uuid="2A00" id="c\_device\_name"> <description>Device Name</description> <properties read="true" const="true" /> <value>BGLib U1A1P 38.4NF</value> </characteristic> <!-- 2A01: org.bluetooth.characteristic.gap.appearance --> <characteristic uuid="2A01" id="c\_appearance"> <description>Appearance</description> <properties read="true" const="true" /> <!-- 128: Generic Computer, Generic category --> <value type="hex">0080</value> </characteristic> </service> <!-- 180A: org.bluetooth.service.device\_information --> <service uuid="180A" id="device\_information"> <description>Device Information</description> <!-- 2A29: org.bluetooth.characteristic.manufacturer\_name\_string --> <!-- (support for this characteristic is MANDATORY according to the profile spec) --> <characteristic uuid="2A29" id="c\_manufacturer\_name"> <description>Manufacturer Name</description> <properties read="true" const="true" /> <value>SectorFej</value> </characteristic> <!-- 2A24: org.bluetooth.characteristic.model\_number\_string --> <characteristic uuid="2A24" id="c\_model\_number"> <description>Model Number</description> <properties read="true" const="true" /> <value>SF-BGLIB</value> </characteristic> </service> <!-- custom service for data transmission test --> <service uuid="195AE58A-437A-489B-B0CD-B7C9C394BAE4" id="data\_transceiver" advertise="true"> <description>Data transceiver service</description> <characteristic uuid="5FC569A0-74A9-4FA4-B8B7-8354C86E45A4" id="c\_rx\_data"> <description>RX Data</description> <properties write="true" /> <value variable\_length="true" length="20"></value> </characteristic> <characteristic uuid="21819AB0-C937-4188-B0DB-B9621E1696CD" id="c\_tx\_data"> <description>TX Data</description> <properties read="true" notify="true" indicate="true" /> <value variable\_length="true" length="20"></value> </characteristic> </service> </configuration>

Do pardon the use of blockquotes, I plan to embed a Github gist when I figure out how.

EDIT @ 4/26/2021: Fixed with markdown.

Note the threes services used:

  1. The Generic Access Service

  2. The Device Information Service

  3. The custom service I'm using to read and write data to the two characteristics I have defined.

Note it is here that the characteristics are assigned whether they are read, write, notification or indication enabled. Also notice that a characteristic can utilize multiple properties, they just have to be specified within the tag.

Next up is the hardware configuration xml:

> <?xml version="1.0" encoding="UTF-8" ?> <hardware> <sleeposc enable="true" ppm="30" /> <usb enable="true" endpoint="api" /> <txpower power="15" bias="5" /> <usart mode="packet" channel="1" alternate="1" baud="38400" endpoint="api" flow="false" /> <!-- UART PIN ASSIGNMENT TABLE: +=========+===========+======+======+======+======+ | channel | alternate | RX | TX | RTS | CTS | +=========+===========+======+======+======+======+ | 0 | 1 | P0\_2 | P0\_3 | P0\_5 | P0\_4 | | 0 | 2 | P1\_4 | P1\_5 | P1\_3 | P1\_2 | | 1 | 1 | P0\_5 | P0\_4 | P0\_3 | P0\_2 | (SELECTED) | 1 | 2 | P1\_7 | P1\_6 | P1\_5 | P1\_4 | +=========+===========+======+======+======+======+ --> <port index="0" pull="down" tristatemask="0" /> <port index="1" pull="down" tristatemask="0" /> <port index="2" pull="down" tristatemask="0" /> </hardware>

As you can see, this is where certain properties of the BLE112 module is set up. The only thing you're likely to want to change here is the baud rate. The others are fairly nuanced and you would do well to read Bluegiga's reference to understand what they are and why you'd want to change them, most especially the wake up pin and flow mode.

All the files above and the actual project file you need to flash the BLE112 can be found on Jeff Rowberg's Github. He's the awesome guy that wrote the BGLib C library. To flash the BLE112, you will need Texas Instrument's CC Debugger. Also, you will need to have access to the pins on the BLE112 to connect it to the debugger. This will be rather difficult if you don't have the BLE112 connected to a breakout board with easy access to the pins. You can buy an already wired breakout board from Jeff Rowberg himself here. It makes it incredibly easy to wire it to an Arduino Uno or whatever Arduino board you have.

In the second link in the above paragraph, you will see that Bluegiga has ported their BGLib library to various platforms so you may interact with the BGAPI used to communicate with the module. I personally am very fond of the C port as it is very easy to use with Arduino. It is what all my examples will be based on.

Also, for more information on characteristic characteristics (I'm immensely proud of that line), see this Bluegiga reference as well.

In the next post, I'll show how to wire the BLE112 to an Arduino UNO.

,