Server APIs
Once the GATT Database has been created and the required security settings have been registered with Gap_RegisterDeviceSecurityRequirements, all ATT Requests and Commands and attribute access security checks are handled internally by the GATT Server module.
Besides this automatic functionality, the application may use GATT Server APIs to send Notifications and Indication and, optionally, to intercept Clients’ attempts to write certain attributes.
Server callback
The first GATT Server call is the installation of the Server Callback, which has the following prototype:
**typedef ****void** (* gattServerCallback_t )
(
deviceId_t deviceId, /*!< Device ID identifying the active connection. */
gattServerEvent_t * pServerEvent /*!< Server event. */
);
For EATT, the following signature should be used:
typedef void (*gattServerEnhancedCallback_t) ( deviceId_t deviceId, bearerId_t bearerId, gattServerEvent_t* pServerEvent );
The callback can be installed with:
bleResult_t **GattServer\_RegisterCallback**
(
gattServerCallback_t callback
);
The EATT server callback should be installed using the following API:
bleResult_t **GattServer\_RegisterEnhancedCallback**
(
gattServerEnhancedCallback_t callback
);
The first member of the gattServerEvent_t structure is the eventType, an enumeration type with the following possible values:
gEvtMtuChanged_c: Signals that the Client-initiated MTU Exchange Procedure has completed successfully and the ATT_MTU has been increased. The event data contains the new value of the ATT_MTU. Is it possible that the application flow depends on the value of the ATT_MTU, for example, there may be specific optimizations for different ATT_MTU ranges. This event is not triggered if the ATT_MTU was not changed during the procedure.
gEvtHandleValueConfirmation_c: A Confirmation was received from the Client after an Indication was sent by the Server.
gEvtAttributeWritten_c, gEvtAttributeWrittenWithoutResponse_c: See Attribute write notifications.
gEvtCharacteristicCccdWritten_c: The Client has written a CCCD. The application should save the CCCD value for bonded devices with Gap_SaveCccd.
gEvtError_c: An error occurred during a Server-initiated procedure.
gEvtLongCharacteristicWritten_c: A long characteristic was written.
gEvtInvalidPduReceived_c: An invalid PDU was received from Client. Application decides if disconnection is required.
gEvtAttributeRead_c: An attribute registered with
GattServer_RegisterHandlesForReadNotifications
is being read.
Parent topic:Server APIs
Sending notifications and indications
The APIs provided for these Server-initiated operations are very similar.
All of the following APIs have an enhanced counterpart of the form GattServer_Enhanced[procedure]. A bearerId parameter was added to specify on which bearer the transaction should take place. A value of 0 for the bearerId identifies the Unenhanced ATT bearer. Values higher than0 are used to identify the Enhanced ATT bearer used for the ATT procedure.
bleResult_t **GattServer\_SendNotification**
(
deviceId_t deviceId,
uint16_t handle
);
bleResult_t **GattServer\_SendIndication
**(
deviceId_t deviceId,
uint16_t handle
);
Only the attribute handle needs to be provided to these functions. The attribute value is automatically retrieved from the GATT Database.
Note: It is the application developer’s responsibility to check if the Client designated by the deviceId has previously activated Notifications/Indications by writing the corresponding CCCD value. To do that, the following GAP APIs should be used:
bleResult_t **Gap\_CheckNotificationStatus
**(
deviceId_t deviceId,
uint16_t handle,
bool_t * pOutIsActive
);
bleResult_t **Gap\_CheckIndicationStatus**
(
deviceId_t deviceId,
uint16_t handle,
bool_t * pOutIsActive
);
Note: It is necessary to use these two functions with the Gap_SaveCccd only for bonded devices, because the data is saved in NVM and reloaded at reconnection. For devices that do not bond, the application may also use its own bookkeeping mechanism.
There is an important difference between sending Notifications and Indications:
The latter can only be sent one at a time. In addition, the application must wait for the Client Confirmation (signaled by the gEvtHandleValueConfirmation_c Server event, or by a gEvtError_c event with gGattClientConfirmationTimeout_c error code) before sending a new Indication. Otherwise, a gEvtError_c event with gGattIndicationAlreadyInProgress_c error code is triggered.
The Notifications can be sent consecutively.
Parent topic:Server APIs
Attribute write notifications
When the GATT Client reads and writes values from/into the Server’s GATT Database, it uses ATT Requests.
The GATT Server module implementation manages these requests and, according to the database security settings and the Client’s security status (authenticated, authorized, and so on), automatically sends the ATT Responses without notifying the application.
There are however some situations where the application needs to be informed of ATT packet exchanges. For example, a lot of standard profiles define, for certain Services, some, so-called, Control-Point Characteristics. These are Characteristics whose values are only of immediate significance to the application. Writing these Characteristics usually triggers specific actions.
For example, consider a fictitious Smart Lamp. It has Bluetooth Low Energy connectivity in the Peripheral role and it contains a small GATT Database with a Lamp Service (among other Services). The Lamp Service contains two Characteristics: the Lamp State Characteristic (LSC) and the Lamp Action Characteristic (LAC).
LSC is a “normal” Characteristic with Read and Write properties. Its value is either 0, lamp off, or 1, lamp on). Writing the value sets the lamp in the desired state. Reading it provides its current state, which is only useful when passing the information remotely.
The LAC has only one property, which is Write Without Response. The user can use the Write Without Response procedure to write only the value 0x01 (all other values are invalid). Whenever the user writes 0x01 in LAC, the lamp switches its state.
The LAC is a good example of a Control-Point Characteristic for these reasons:
Writing a certain value (in this case 0x01) triggers an action on the lamp.
The value the user writes has immediate significance only (“0x01 switches the lamp”) and is never used again in the future. For this reason, it does not need to be stored in the database.
Obviously, whenever a Control-Point Characteristic is written, the application must be notified to trigger some application-specific action.
The GATT Server allows the application to register a set of attribute handles as “write-notifiable”, in other words, the application wants to receive an event each time any of these attributes is written by the peer Client.
All Control-Point Characteristics in the GATT Database must have their Value handle registered. In fact, the application may register any other handle for write notifications for its own purposes with the following API:
bleResult_t **GattServer\_RegisterHandlesForWriteNotifications**
(
uint8_t handleCount,
const uint16_t * aAttributeHandles
);
The handleCount is the size of the aAttributeHandles array and it cannot exceed gcGattMaxHandleCountForWriteNotifications_c.
After an attribute handle has been registered with this function, whenever the Client attempts to write its value, the GATT Server Callback is triggered with one of the following event types:
gEvtAttributeWritten_c is triggered when the attribute is written with a Write procedure (ATT Write Request). In this instance, the application has to decide whether the written value is valid and whether it must be written in the database, and, if so, the application must write the value with the GattDb_WriteAttribute, see GATT database application interface. At this point, the GATT Server module does not automatically send the ATT Write Response over the air. Instead, it waits for the application to call this function:
bleResult_t **GattServer\_SendAttributeWrittenStatus**
(
deviceId_t deviceId,
uint16_t attributeHandle,
uint8_t status
);
This API also has an enhanced counterpart, which adds the bearerId parameter.
The value of the status parameter is interpreted as an ATT Error Code. It must be equal to the gAttErrCodeNoError_c (0x00) if the value is valid and it is successfully processed by the application. Otherwise, it must be equal to a profile-specific error code (in interval 0xE0-0xFF) or an application-specific error code (in interval 0x80-0x9F).
gEvtAttributeWrittenWithoutResponse_c is triggered when the attribute is written with a Write Without Response procedure (ATT Write Command). Because this procedure expects no response, the application may process it and, if necessary, write it in the database. Regardless of whether the value is valid or not, no response is needed from the application.
gEvtLongCharacteristicWritten_c is triggered when the Client has completed writing a Long Characteristic value; the event data includes the handle of the Characteristic Value attribute and a pointer to its value in the database.
Attributes can also be registered for read notifications using the followng API:
bleResult_t GattServer_RegisterHandlesForReadNotifications
(
uint8_t handleCount,
const uint16_t* aAttributeHandles
);
To unregister one or more handles from the list for either write or read, the following APIs can be used:
bleResult_t GattServer_UnregisterHandlesForWriteNotifications
(
uint8_t handleCount,
const uint16_t* aAttributeHandles
);
bleResult_t GattServer_UnregisterHandlesForReadNotifications
(
uint8_t handleCount,
const uint16_t* aAttributeHandles
);
Parent topic:Server APIs
Parent topic:Generic Attribute Profile (GATT) Layer