Hey folks, I am back with another article on Bluetooth Low Energy (BLE). In my previous article, I addressed some common misconceptions between classic Bluetooth and BLE. This time, I will be talking about one of the most commonly used profiles for a BLE device – the GATT, also known as the Generic Attribute Profile.
Before I begin, let’s start with a good ol’ history lesson. You may ask why. Simply because I love history, and I promise it’s a short one.
BLE was not always known as Bluetooth Low Energy. It was first conceived by Nokia in 2006 as Wibree. Then, it was touted to be a competitor to Bluetooth and there were articles on how Wibree might replace Bluetooth in some use cases. However, as we all know by now, that didn’t happen because Bluetooth SIG absorbed Wibree in 2010 into its current Bluetooth v4.0 specifications and BLE was born. As always, we have to thank Nokia for laying the foundation of many good wireless technologies that we have come to enjoy today. Nokia 3210, I will always love you for being my first… mobile phone.
With the history lesson behind us, let’s move on with the introduction of BLE profiles and protocols.
For BLE, you will use one of the following profiles or protocols:
- GATT-based profiles
- BR/EDR profiles
- BR/EDR protocols
I will focus on GATT-based profiles as they are the most commonly used profiles in data-transfer applications.
When one looks deeper into the GATT-based profiles, one will quickly discover that Bluetooth SIG has defined many profiles for generic IoT usage. Of course, you can also design a custom profile if none of them suits your use case. However, there are reasons that Bluetooth SIG has a predefined profile.
First, a predefined profile is kind of like a “plug and play” element in your design. Most BLE-chip software development kits (SDKs) would support some of such profiles and all you have to do is to enable them. This saves a lot of time for developers.
Second, the predefined profile uses the 16-bit universally unique identifier (UUID) because it has been approved by Bluetooth SIG. A custom profile needs to use a 128-bit UUID to prevent collision with an existing UUID (if any) and for future-proofing the design.
Having said so, a predefined profile will not be flexible when you need to transmit information that is not in the predefined list. When that happens, you will need a custom profile. At this junction, I know that some of you guys may have the tendency to “retrofit” a predefined profile for your use case, but I will not recommend that. It is better to define a custom one from scratch.
Pros-and-cons summary table
As much I wish to go into great detail on the deep, deep abyss of BLE, I will give only an overview to get you chaps started. Ok, maybe it’s not that deep of an abyss and maybe it’s a shiny piece of heaven to some of you chaps. I will give only an overview. For those who wish to learn more about BLE, do read this.
The best way to get started is to have a graphical representation of the GATT profile.
When it comes to designing a profile, there are three attributes that must be taken care of – namely service, characteristic and descriptor. Each attribute is demarcated by a handler number which is usually enumerated automatically by your Bluetooth chip SDK. If your SDK does not take care of that, I will just say “have fun enumerating”. So to prevent making a mess out of your code, it’s better to design and reiterate before you jump into your code, you code monkeys.
One good note when it comes to designing a profile is that it’s not necessary for a characteristic to hold a descriptor, but it’s mandatory for a service to hold at least one characteristic.
There are two types of services – primary and secondary. Usually, developers will use only the primary service because the secondary service can exist only under the primary service, which makes it a little tricky to use. Within a profile, you may find multiple primary services. For example, a standard heart-rate tracker will have the following services:
- Device information service
- Battery information service
- Heart-rate service
Note that all of them are predefined services. You are encouraged to create your own service if none of the standard services fits your usage, modification to the service may yield unexpected results and it’s recommended that you write your own service characteristics.
So if you look at the above graphic, you can think of service as a container for all your characteristics. During device advertising, you would usually include the UUID of the key primary services so your remote client will discover the right device.
A characteristic is a data container for the information that your device wishes to transmit to your remote client. For example, a heart-rate service will have a Heart-Rate Measurement characteristic to hold the heart rate that your device has detected.
When declaring a characteristic, you will also determine the permission level for the characteristic:
- Write with response
- Signed write
- Writable Auxiliaries
The most common permissions would be read and write. One a side note, if you wish to push your data to your remote client, you will need to enable the notify permission. However, enabling the notify permission is not enough, you will also need to include the notify switch descriptor, also known as Client Characteristic Configuration Descriptor or CCCD.
As mentioned previously, it is not entirely necessary for a characteristic to be accompanied by a descriptor. A question that a reader might ask is, under what circumstance would you include a descriptor? That would be when you wish to describe a characteristic (like its name or function) or to include a notify switch. For the former, you would include a “Characteristic User Description” and for the latter, you would include a “Client Characteristic Configuration Descriptor”.
In a nutshell, you use a predefined profile if the standard profile is good enough for you, and a custom one if you know what you are doing.
For a firmware designer, you have to take note that the BLE GATT profile is by no mean persistent. You will need some form of non-volatile memory to hold your default values or previously captured data and instantiate your GATT profile during each device restart or power up.
Now go forth and code away!
Build the future.