Just as the GAP layer handles most connection-related functionality,
the GATT layer of the Bluetooth low energy protocol stack is used by
the application for data communication between two connected
devices. Data is passed and stored in the form of characteristics
which are stored in memory on the Bluetooth low energy device. From
a GATT standpoint, when two devices are connected they are each in
one of two roles.

The GATT server

the device containing the characteristic
database that is being read or written by a GATT client.

The GATT client

the device that is reading or writing data
from or to the GATT server.

Figure 40. shows this relationship in a sample Bluetooth low
energy connection where the peripheral device (that is, a CC2640R2 Launchpad)
is the GATT server and the central device (that is, a smart phone) is the GATT
client.

Figure 40. GATT Client and Server Interaction Overview

The GATT roles of client and server are independent from the GAP
roles of peripheral and central. A peripheral can be either a GATT
client or a GATT server, and a central can be either a GATT client
or a GATT server. A peripheral can act as both a GATT client and a
GATT server. For a hands-on review of GATT services and
characteristics, see SimpleLink Academy.

While characteristics and attributes are sometimes used
interchangeably when referring to Bluetooth low energy, consider
characteristics as groups of information called attributes.
Attributes are the information actually transferred between devices.
Characteristics organize and use attributes as data values,
properties, and configuration information. A typical characteristic
is composed of the following attributes.

Characteristic Value

data value of the characteristic

Characteristic Declaration

descriptor storing the properties,
location, and type of the characteristic value

Client Characteristic Configuration

a configuration that allows the GATT server to
configure the characteristic to be notified (send message
asynchronously) or indicated (send message asynchronously
with acknowledgment)

Characteristic User Description

an ASCII string describing the characteristic

These attributes are stored in the GATT server in an attribute
table. In addition to the value, the following properties are
associated with each attribute.

Handle

the index of the attribute in the table (Every attribute has
a unique handle.)

Type

indicates what the attribute data represents (referred to as a
UUID [universal unique identifier]. Some of these are Bluetooth
SIG-defined and some are custom.)

Permissions

enforces if and how a GATT client device can access the
value of an attribute

Like the GAP layer, the GATT layer is also abstracted. This
abstraction depends on whether the device is acting as a GATT client
or a GATT server. As defined by the Bluetooth Core Specification Version 4.2, the
GATT layer is an abstraction of the ATT layer.

GATT clients do not have attribute tables or profiles as they are
gathering, not serving, information. Most of the interfacing with
the GATT layer occurs directly from the application.

As a GATT server, most of the GATT functionality is handled by the
individual GATT profiles. These profiles use the
GATTServApp ( see BLE Stack API Reference, GATTServApp Section) (a
configurable module that stores and manages the attribute table).
Figure 42. shows this abstraction hierarchy.

Figure 42. Visualization of GATT Server abstraction.

The design process involves creating GATT profiles that configure
the GATTServApp module and use its API to interface with the GATT
layer. In this case of a GATT server, direct calls to GATT layer
functions are unnecessary. The application then interfaces with the
profiles.

A GATT service is a collection of characteristics. For example, the
heart rate service contains a heart rate measurement characteristic
and a body location characteristic, among others. Multiple services
can be grouped together to form a profile. Many profiles only
implement one service so the two terms are sometimes used
interchangeably.

Note

TI intends this section as an introduction to the attribute
table by using simple_peripheral as an example. For information on how this
profile is implemented within the stack, see GATT Server Abstraction.

There are four GATT profiles defined in the simple_peripheral example
application project.

This service contains information about
the GATT server, is a part of the Bluetooth low energy protocol
stack, and is required for every GATT server device as per the
Bluetooth Core Specification Version 4.2.

Device Info Service

This service exposes information about the
device such as the hardware, software version, firmware version,
regulatory information, compliance information, and manufacturer
name. The Device Info Service is part of the Bluetooth low energy
protocol stack and configured by the application.

simple_gatt_profile Service

This service is a sample profile for
testing and for demonstration. The full source code is provided
in the simple_gatt_profile.c and simple_gatt_profile.h files.

Figure 43. shows the attribute table in the
simple_peripheral project.

1-byte value that can be read from a GATT client device but cannot be
written

SIMPLEPROFILE_CHAR3

1-byte value that can be written from a GATT client device but cannot be
read

SIMPLEPROFILE_CHAR4

1-byte value that cannot be directly read or written from a GATT client
device (This value is notifiable: This value can be configured for
notifications to be sent to a GATT client device.)

SIMPLEPROFILE_CHAR5

5-byte value that can be read (but not written) from a GATT client device

The following is a line-by-line description of the simple profile attribute
table, referenced by the following handle.

0x001C is the simple_gatt_profile service declaration.

This declaration has a UUID of 0x2800 (Bluetooth-defined
GATT_PRIMARY_SERVICE_UUID). The value of this declaration is
the UUID of the simple_gatt_profile (custom-defined).

0x001D is the SimpleProfileChar1 characteristic declaration.

This declaration can be thought of as a pointer to the
SimpleProfileChar1 value. The declaration has a UUID of 0x2803
(Bluetooth-defined GATT_CHARACTER_UUID). The value of the
declaration characteristic, as well as all other characteristic
declarations, is a 5-byte value explained here (from MSB to LSB):

The value of 0x0A means the characteristic is readable (0x02) and
writeable (0x08).

Bytes 1-2: the byte-reversed handle where the SimpleProfileChar1’s
value is (handle 0x001E)

Bytes 3-4: the UUID of the SimpleProfileChar1 value (custom-defined
0xFFF1)

0x001E is the SimpleProfileChar1 Characteristic Value

This value has a UUID of
0xFFF1 (custom-defined). This value is the actual payload data of
the characteristic. As indicated by its characteristic
declaration (handle 0x01D), this value is readable and
writable.

0x001F is the SimpleProfileChar1 Characteristic User Description

This description has a UUID of 0x2901 (Bluetooth-defined). The value of
this description is a user-readable string describing the characteristic.

0x0020 - 0x002C

are attributes that follow the same structure as the simpleProfileChar1
described previously with regard to the remaining four characteristics.
The only different attribute, handle 0x0028, is described as follows.

0x0028 is the SimpleProfileChar4 Client Characteristic Configuration.
This configuration has a UUID of 0x2902 (Bluetooth-defined). By
writing to this attribute, a GATT server can configure the
SimpleProfileChar4 for notifications (writing 0x0001) or
indications (writing 0x0002). Writing 0x0000 to this attribute
disable notifications and indications.

As described in GATT Server Abstraction, the GATT server may define
permissions independently for each characteristic. The server may
allow some characteristics to be accessed by any client, while
limiting access to other characteristics to only authenticated or
authorized clients. These permissions are usually defined as part of
a higher level profile specification. For custom profiles, the user
may select the permissions as they see fit. For more information
about the GATT Security, refer to the Security Considerations section
([Vol 3], Part G, Section 8) of the Bluetooth Core Specification Version 4.2.

Characteristics that require authentication cannot be accessed until
the client has gone through an authenticated pairing method. This
verification is performed within the stack, with no processing
required by the application. The only requirement is for the
characteristic to be registered properly with the GATT server.

For example, characteristic 5 of the simple_gatt_profile allows on
authenticated reads.

When an un-authenticated client attempts to read this value, the GATT
server automatically rejects it with ERROR_INSUFFICIENT_AUTHEN(0x41),
without invoking the simpleProfile_ReadAttrCB(). See an example of this
in Sniffer Capture Example.

Figure 44. Sniffer Capture Example

After the client has successfully authenticated, read/write requests
are forwarded to the profiles read/write callback. See the code
below for a simple_gatt_profile example:

Authorization is a layer of security provided in addition to what
BLE already implements. Because applications are required to define
their own requirements for authorization, the stack forwards
read/write requests on these characteristics to the application
layer of the profile.

For the profile to register for authorization information from the
GATT server, it must define an authorization callback with the
stack. The simple_gatt_profile does not do this by default, but
below is an example of how it could be modified to do this.

staticbStatus_tsimpleProfile_authorizationCB(uint16connHandle,gattAttribute_t*pAttr,uint8opcode){//This is just an example implementation, normal use cases would require//more complex logic to determine that the device is authorizedif(clientIsAuthorized)returnSUCCESS;elsereturnATT_ERR_INSUFFICIENT_AUTHOR;}

The authorization callback executes in the stack context, thus
intensive processing should not be performed in this function. The
implementation is left up to the developer; the above callback
should be treated as a shell. The return value should be either
SUCCESS if the client is authorized to access the characteristic, or
ATT_ERR_INSUFFICIENT_AUTHOR if they have not yet obtained proper
authorization. Authorization requires the connection to be authenticated
beforehand, or ATT_ERR_INSUFFICIENT_AUTHEN will be sent as an error
response.

If a characteristic that requires authorization is registered with
the GATT server, but no application level authorization callback is
defined, the stack will return ATT_ERR_UNLIKELY. Because this
error can be cryptic, TI recommends using an authorization callback.

This section describes how to use the GATT layer in an application.
The functionality of the GATT layer is implemented in the library
but header functions can be found in the gatt.h file.
The BLE Stack API Reference within the ATT/GATT section has
the complete API for the GATT layer. The Bluetooth Core Specification Version 4.2
provides more information on the functionality of these commands. These
functions are used primarily for GATT client applications. A few server-specific
functions are described in the API. Most of the GATT functions
returns ATT events to the application, review BLE Stack API Reference for details.

The general procedure to use the GATT layer when functioning as a GATT client
(in the simple_central project) is as follows:

Even though the event sent to the application is an ATT
event, it is sent as a GATT protocol stack message
(GATT_MSG_EVENT).

Note

In addition to receiving responses to its own commands, a GATT client may
also receive asynchronous data from the GATT server as indications or
notifications. Use (GATT_RegisterForInd(selfEntity)) to receive these
ATT notifications and indications. These notifications and indications are
also sent as ATT events (ATT_HANDLE_VALUE_NOTI &
ATT_HANDLE_VALUE_IND) in GATT messages to the application. These events
must be handled as described in GATT Services and Profile.

The GAP GATT Service (GGS) is required for low-energy devices that
implement the central or peripheral role. Multirole devices that
implement either of these roles must also contain the GGS. The
purpose of the GGS is to aide in the device discovery and connection
initiation process.

This section describes what the application must do to configure,
start, and use the GAP Gatt Service. The GGS is implemented as part
of the Bluetooth Low Energy library code, the API can be found in
GATTServApp. ATT/GATT describes the full API,
including commands, configurable parameters, events, and callbacks.

The service changed characteristic is used to inform bonded devices
that services have changed on the server upon reconnection. Service
changed updates are sent in the form of GATT indications, and the
service changed characteristic is not writeable or readable. In the
TI Bluetooth low energy stack, the service changed characteristic is
implemented as part of the gattservapp, which is part of library
code.

Per the Bluetooth Core Specification Version 4.2, it is safe for server
devices whose characteristic tables do not change over their
lifetime to exclude the service changed characteristic. Support for
indications from this characteristic must be supported on GATT
client devices.

This section describes what the user must do to enable the GATT
service changed feature in the Bluetooth low energy stack. Once the
service changed feature is enabled, the GAPBondMgr will handle
sending the service changed indication to clients who have enabled
it using the CCCD.

Use a supported build config for the stack; only stack libraries with
v4.1 features and L2CAP connection-oriented channels will support
the service changed characteristic.

Enable this feature with the project’s build_config.opt file, by
uncommenting the following line:

-DBLE_V41_FEATURES=L2CAP_COC_CFG+V41_CTRL_CFG

From this point, the GAPBondMgr handles sending an indication to
connected clients when the service has changed and the CCCD is
enabled. If the feature is enabled, the peripheral role invokes
the necessary APIs to send the indication through the GAPBondMgr.

On the client side, service changed indications can be registered
using the same method as registering for other indications.

The GATT Server Application (GATTServApp) stores and manages the application-wide attribute
table. Various profiles use this module to add their characteristics
to the attribute table. The Bluetooth low energy stack uses this
module to respond to discovery requests from a GATT client. For
example, a GATT client may send a Discover all Primary
Characteristics message. The Bluetooth low energy stack on the GATT
server side receives this message and uses the GATTServApp to find and
send over-the-air all of the primary characteristics stored in the
attribute table. This type of functionality is beyond the scope of
this document and is implemented in the library code. The
GATTServApp functions accessible from the profiles are defined in
‘’gattservapp_util.c’’ and the API described in BLE Stack API Reference
(GATTServApp section).
These functions include finding specific attributes and reading or modifying
client characteristic configurations. See Figure 46. for an
example of how GATTServApp functions in an application.

Upon power-on or reset, the application builds the GATT table by
using the GATTServApp to add services. Each service consists of a
list of attributes with UUIDs, values, permissions, and read and
write call-backs. As Figure 46. shows, all of this
information is passed through the GATTServApp to GATT and stored in the stack.

Attribute table initialization must occur in the application
initialization function, that is, simple_peripheral_init().

This section describes the general architecture for implementing profiles and
provides specific functional examples in relation to the
simple_gatt_profile in the simple_peripheral project. See
GATT Services and Profile for an overview of the simple_gatt_profile.

When utilizing gattAttribute_t, the various fields have specific meanings.

gattAttrType_t type

type is the UUID associated with the attribute being placed into the table. gattAttrType_t itself is defined as:

typedefstruct{uint8len;//!< Length of UUID (2 or 16)constuint8*uuid;//!<Pointer to UUID}gattAttrType_t;

Where length can be either ATT_BT_UUID_SIZE (2 bytes), or
ATT_UUID_SIZE (16 bytes). The *uuid is a pointer to a number either
reserved by Bluetooth SIG (defined in gatt_uuid.c) or a custom UUID
defined in the profile.

uint8 permissions

enforces how and if a GATT client device can access the
value of the attribute. Possible permissions are defined in
gatt.h as follows:

The type is set to the Bluetooth SIG-defined primary service UUID
(0x2800). A GATT client is permitted to read this service with the permission
is set to GATT_PERMIT_READ. The pValue is a pointer to the UUID of
the service, custom-defined as 0xFFF0. SimpleProfileService itself is defined to
reference the profile’s UUID.

The type is set to the Bluetooth SIG-defined characteristic UUID
(0x2803). This makes simpleProfileCharacteristic1 read only to the GATT client
with the permissions set to GATT_PERMIT_READ.

For functional purposes, the only information required to be passed
to the GATTServApp in pValue is a pointer to the properties of the
characteristic value. The GATTServApp adds the UUID and the handle
of the value. These properties are defined to allow this particular
characteristic in this service to be read and written to.

An important distinction exists between these properties
and the GATT permissions of the characteristic value. These
properties are visible to the GATT client stating the properties of
the characteristic value. The GATT permissions of the characteristic
value affect its functionality in the protocol stack. These
properties must match that of the GATT permissions of the
characteristic value.

The type is set to the custom-defined simpleProfilechar1 UUID
(0xFFF1). The properties of the characteristic value in the attribute
table must match the properties from the characteristic value
declaration. The pValue is a pointer to the location of the actual
value, statically defined in the profile as follows.

The type is set to the Bluetooth SIG-defined client characteristic
configuration UUID (0x2902) GATT clients must read and write to this
attribute so the GATT permissions are set to readable and writable.
The pValue is a pointer to the location of the client characteristic
configuration array, defined in the profile as follows.

Client characteristic configuration is represented as an
array because this value must be cached for each connection. The
catching of the client characteristic configuration is described in
more detail in Add Service Function.

As described in GATTServApp Module, when an application starts up it
requires adding the GATT services it supports. Each profile needs a
global AddService function that can be called from the application.
Some of these services are defined in the protocol stack, such as
GAP GATT Service and GATT Service. User-defined services must expose
their own AddService function that the application can call for
profile initialization. Using SimpleProfile_AddService() as an
example, these functions should do as follows.

Allocate space for the client characteristic configuration (CCC)
arrays. As an example, a pointer to one of these arrays was
initialized in the profile as described in
ref:client_characteristic_configuration.

In the AddService function, the supported connections is declared and memory
is allocated for each array. Only one CCC is defined in the
imple_gatt_profile but there can be multiple CCCs.

Initialize the CCC arrays. CCC values are persistent between power
downs and between bonded device connections. For each CCC in the
profile, the GATTServApp_InitCharCfg() function must be called.
This function tries to initialize the CCCs with information from
a previously bonded connection and set the initial values to
default values if not found.

1

GATTServApp_InitCharCfg(INVALID_CONHANDLE,simpleProfileChar4Config);

Register the profile with the GATTServApp. This function passes the
attribute table of the profile to the GATTServApp so that the
attributes of the profile are added to the application-wide
attribute table managed by the protocol stack and handles are
assigned for each attribute. This also passes pointers to the
callbacks of the profile to the stack to initiate communication
between the GATTServApp and the profile.

Profiles can relay messages to the application using callbacks. In
the simple_peripheral project, the simple_gatt_profile calls an
application callback whenever the GATT client writes a
characteristic value. For these application callbacks to be used,
the profile must define a Register Application Callback function
that the application uses to set up callbacks during its
initialization. The register application callback function for the
simple_gatt_profile is the following:

The profile must define Read and Write callback functions which the
protocol stack calls when one of the attributes of the profile are
written to or read from. The callbacks must be registered with
GATTServApp as mentioned in Add Service Function. These callbacks
perform the characteristic read or write and other processing (possibly calling
an application callback) as defined by the specific profile.

When a read request from a GATT Client is received for a given
attribute, the protocol stack checks the permissions of the
attribute and, if the attribute is readable, calls the read call-back
profile. The profile copies in the value, performs any
profile-specific processing, and notifies the application if
desired. This procedure is illustrated in Figure 47. for a read
of simpleprofileChar1 in the simple_gatt_profile.

The processing is in the context of the protocol stack. If any
intensive profile-related processing that must be done in the case
of an attribute read, this should be split up and done in the
context of the Application task. See the Write Request from Client for
more information.

When a write request from a GATT client is received for a given
attribute, the protocol stack checks the permissions of the
attribute and, if the attribute is write-permitted, calls the write callback of
the profile. The profile stores the value to be written, performs
any profile-specific processing, and notifies the application if
desired. Figure 48. shows this procedure for a write
of simpleprofileChar3 in the simple_gatt_profile.

Minimizing the processing in protocol stack context is
important. In this example, additional processing beyond storing the
attribute write value in the profile occurs in the application context by enqueuing a message in the
queue of the application.

The profile containing the characteristics shall provide set and get
abstraction functions for the application to read and write a
characteristic of the profile. The set parameter function also
includes logic to check for and implement notifications and
indications if the relevant characteristic has notify or indicate
properties. Figure 49. and the following code show this example
for setting simpleProfileChacteristic4 in the simple_gatt_profile.

The code for this function is displayed in the following code
snippet (from simple_gatt_profile.c). Besides setting the value of
the static simpleProfileChar4, this function also calls
GATTServApp_ProcessCharCfg() because it has notify properties. This
action forces GATTServApp to check if notifications have been
enabled by the GATT Client. If so, the GATTServApp sends a
notification of this attribute to the GATT Client.

bStatus_tSimpleProfile_SetParameter(uint8param,uint8len,void*value){bStatus_tret=SUCCESSswitch(param){caseSIMPLEPROFILE_CHAR4:if(len==sizeof(uint8)){simpleProfileChar4=*((uint8*)value);// See if Notification has been enabledGATTServApp_ProcessCharCfg(simpleProfileChar4Config,&simpleProfileChar4,FALSE,simpleProfileAttrTbl,GATT_NUM_ATTRS(simpleProfileAttrTbl),INVALID_TASK_ID,simpleProfile_ReadAttrCB);}

Prepare Write commands allows a GATT server to send more payload
data by queuing up multiple write requests. The default queue size
is 5. With a default MTU of 23 and payload of 18 bytes, up to 90
bytes of payload can be sent. For more information on queued writes, refer to
the Queued Writes section ([Vol 3], Part F, Section 3.4.6) of the Bluetooth Core Specification Version 4.2.

Adjust the Prepare Write queue with GATTServApp_SetParameter() with
parameter GATT_PARAM_NUM_PREPARE_WRITES. There is no specified
limit, but it is bounded by the available HEAPMGR space.

To support fragmentation, GATT and ATT payload structures must be
dynamically allocated for commands sent wirelessly. For example, a
buffer must be allocated when sending a GATT_Notification. The
stack does this allocation if the preferred method to send a GATT
notification or indication is used: calling a SetParameter function
of the profile (that is, SimpleProfile_SetParameter()) and calling
GATTServApp_ProcessCharCfg() as described in
Get and Set Functions.

Using GATT_RegisterForMsgs(), receiving additional
GATT messages to handle certain corner cases is possible. This
possibility can be seen in simple_peripheral_processGATTMsg(). The
following three cases are currently handled.

GATT server in the stack was unable to send an ATT response (due to
lack of available HCI buffers): Attempt to transmit on the next
connection interval. Additionally, a status of bleTimeout is sent
if the ATT transaction is not completed within 30 seconds, as
specified in the Bluetooth Core Specification Version 4.2.

Listing 66. See if GATT server was unable to transmit an ATT response.¶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// See if GATT server was unable to transmit an ATT responseif(pMsg->hdr.status==blePending){//No HCI buffer was available. Let's try to retransmit the response//on the next connection event.if(HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle,selfEntity,SBP_CONN_EVT_END_EVT)==SUCCESS){//First free any pending responseSimpleBLEPeripheral_freeAttRsp(FAILURE);//Hold on to the response message for retransmissionpAttRsp=pMsg;//Don't free the response message yetreturn(FALSE);}}

An ATT flow control violation: The application is notified that the
connected device has violated the ATT flow control specification,
such as sending a Read Request before an Indication Confirm is
sent.

No more ATT requests or indications can be sent wirelessly during the
connection. The application may want to terminate the connection due to this
violation. As an example in simple_peripheral, the LCD is updated.

elseif(pMsg->method==ATT_FLOW_CTRL_VIOLATED_EVENT){//ATT request-response or indication-confirmation flow control is//violated. All subsequent ATT requests or indications will be dropped.//The app is informed in case it wants to drop the connection.//Display the opcode of the message that caused the violation.DISPLAY_WRITE_STRING_VALUE("FC Violated: %d",pMsg->msg.flowCtrlEvt.opcode,LCD_PAGE5);}

An ATT MTU size is updated: The application is notified in case this
affects its processing in any way. See Maximum Transmission Unit (MTU)
for more information on the MTU. As an example in simple_peripheral, the LCD
is updated.