BLE ATT and GATT
GATT stands for Generic Attribute Profile. To understand what GATT is, we first need to understand the underlying framework for GATT: the Attribute Protocol (ATT). The GATT only comes into play after a connection has been established between two BLE devices.
Attribute Protocol (ATT)
ATT defines how a server exposes its data to a client and how this data is structured. There are two roles within the ATT:
Server
This is the device that exposes the data it controls or contains, and possibly some other aspects of server behavior that other devices may be able to control.
It is the device that accepts incoming commands from a peer device and sends responses, notifications and indications.
For example, a thermometer device will behave as a server when it exposes the temperature of its surrounding environment, the unit of measurement, its battery level, and possibly the time intervals at which the thermometer reads and records the temperature. It can also notify the client when a temperature reading has changed rather than have the client poll for the data waiting for a change to occur.
Client
This is the device that interfaces with the server to read the serverʼs exposed data and/or control the serverʼs behavior.
It is the device that sends commands and requests and accepts incoming notifications and indications.
In the previous example, a mobile device that connects to the thermometer and reads its temperature value is acting in the Client role.
The data that the server exposes is structured as attributes. An attribute is the generic term for any type of data exposed by the server and defines the structure of this data. For example, services and characteristics are types of attributes.
Attributes are made up of the following:
Attribute type (Universally Unique Identifier or UUID)
This is a 16-bit number (in the case of Bluetooth SIG-Adopted Attributes), or 128-bit number (in the case of custom attribute types defined by the developer, also sometimes referred to as vendor-specific UUIDs).
For example, the UUID for a SIG-adopted temperature measurement value is 0x2A1C. SIG-adopted attribute types (UUIDs) share all but 16 bits of a special 128-bit base UUID:
0000**0000**-0000-1000-8000-00805F9B34FB
The published 16-bit UUID value replaces the 2 bytes in bold (highlighted) in the base UUID.
A Custom UUID, on the other hand, can be any 128-bit number that does not use the SIG-adopted base UUID. For example, a developer can define their own attribute type (UUID) for a temperature reading as:
F5A1287E-227D-4C9E-AD2C-11D0FD6ED640
One benefit of using a SIG-adopted UUID is the reduced packet size since it can be transmitted as the 16-bit representation instead of the full 128-bit value.Attribute Handle
This is a 16-bit value that the server assigns to each of its attributes (think of it as an address) and is guaranteed to uniquely identify the attribute during the life of the connection between two devices. The range of handles is 0x0001-0xFFFF, where the value of 0x0000 is reserved.
This value is used by the client to reference a specific attribute.Attribute Permissions
Permissions determine whether an attribute can be read or written to, notified or indicated, and the Security Levels required for each operation.
These permissions are not defined or discovered via the Attribute Protocol (ATT), but rather defined at a higher layer (GATT layer or Application layer).
The following figure shows a logical representation of an Attribute:
Generic Attribute Profile (GATT)
After covering the concept of attributes, there are three important concepts in BLE that you will come across very often:
Services
Characteristics
Profiles
These concepts are used specifically to allow hierarchy in the structuring of the data exposed by the Server. Services and characteristics are types of attributes that serve a specific purpose. Characteristics are the lowest level attribute within a database of attributes. Profiles are a bit different and are not discovered on a server.
The GATT defines the format of services and their characteristics, and the procedures that are used to interface with these attributes such as service discovery, characteristic reads, characteristic writes, notifications, and indications.
GATT takes on the same roles as the Attribute Protocol (ATT). The roles are not set per device — rather they are determined per transaction (such as request ⟷ response, indication ⟷ confirmation, notification). So, in this sense, a device can act as a server serving up data for clients, and at the same time act as a client reading data served up by other servers (all during the same connection).
Attribute Operations
There are six different types of attribute operations:
Commands: sent by the client to the server and do not require a response.
Requests: sent by the client to the server and require a response.
There are two types of requests:Find Information Request
Read Request
Responses: sent by the server in response to a request.
Notifications: sent by the server to the client to let the client know that a specific characteristic value has changed.
For this to be triggered and sent by the server, the client has to enable notifications for the characteristic of interest. Note that a notification does not require a response from the client to acknowledge its receipt.Indications: sent by the server to the client. They are very similar to notifications, but require an acknowledgment to be sent back from the client to let the server know that the indication was successfully received.
Confirmations: sent by the client to the server. These are the acknowledgment packets sent back to the server to let it know that the client successfully received an indication.
Notifications and Indications are exposed via the Client Characteristic Configuration Descriptor (CCCD) attribute.
Writing “1” to this attribute value enables notifications.
Writing “2” enables indications.
Writing “0” disables both notifications and indications.
Flow Control and Sequence of Attribute Operations
Requests are sequential and require a response from the server before a new request can be sent. Indications have the same requirement: a new indication cannot be sent before a confirmation for the previous indication is received by the server.
Requests and Indications, however, are mutually exclusive in terms of the sequence requirement. So, an indication can be sent by the server before it responds to a request that it had received earlier.
Commands and Notifications are different, and do not require any flow control — they can be sent at any time. Because of this — and because a server or client may not be able to handle these packets (due to buffer or processing limitations) — they are considered unreliable. When reliability is a concern, requests and indications should be used instead.
Reading Attributes
Reads are requests by nature since they require a response. There are different types of reads. Here we list the two most important ones:
Read Request: a simple request referencing the attribute to be read by its handle.
Read Blob Request: similar to the read request but adds an offset to indicate where the read should start, returning a portion of the value. This type of reading is used for reading only part of a characteristic's value.
Writing To Attributes
Writes can be either commands or requests. Here are the most common types of writes:
Write Request: as the name suggests, this requires a response from the server to acknowledge that the attribute has been successfully written to.
Write Command: this has no response from the server.
Queued Writes (atomic operation behavior): these are classified as requests and require a response from the server. They are used whenever a large value needs to be written and does not fit within a single message.
Instead of writing parts of the value and risking someone else reading the incorrect (partial) value, two types of write requests are used to make sure the operation completes safely:One or more Prepare Write Requests: each includes an offset at which the sent value should be written within the attribute value. The sent values are also referred to as Prepared Values, and they get stored in a buffer on the server side — not written to the attribute yet. This operation requires a response from the server.
One Execute Write Request: used to request from the server to either execute or cancel the write operation of the prepared values.
It requires a response from the server and once a response has been received from the server, the client can now be sure that the attribute holds the complete value it sent to the server.
Exchange MTU Request
The server and the client agree on a common value that is used for both data transfer directions. The client is the side that sends this exchange MTU request packet and can only send it once per connection.
The server then responds with an exchange MTU response packet indicating the ATT_MTU it can support. The agreed-on value then becomes the minimum of the ATT_MTU values exchanged between the client and server.
It is important to know that different BLE stacks have different maximum values of ATT_MTU that they can support.
Subscribe to my newsletter
Read articles from Ahmed Gouda directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ahmed Gouda
Ahmed Gouda
Embedded Software Engineer who are interested in Embedded Systems Design, Embedded Software, Electrical Engineering, and Electronics, C\C++ programming, Assembly, Computer Architecture, Microprocessors, Microcontrollers, and Communication Protocols.