GATT Server#

Generic Attribute Profile (GATT) server implementation: services, characteristics, host- vs firmware-maintained attributes, and notifications/indications from the server.

GATT Server Implementation#

The Generic Attribute Profile (GATT) server is the data model used by Bluetooth Low Energy (BLE) devices to expose services and characteristics. This section describes implementing a GATT server, which is commonly used by peripheral devices.

Note: While peripherals commonly act as GATT servers, GATT roles (Client/Server) are independent of GAP roles (Central/Peripheral). A peripheral can also act as a GATT client, and a central can act as a GATT server.

GATT Server Architecture#

GATT Database Structure:

Service
  ├── Included Service (optional)
  ├── Characteristic 1
  │     ├── Value
  │     ├── Descriptor (e.g., Client Characteristic Configuration)
  │     └── Descriptor (e.g., User Description)
  ├── Characteristic 2
  │     └── ...

Key Concepts:

  • Service: Collection of related characteristics (for example, Battery Service, Heart Rate Service)

  • Characteristic: Data value with properties (read, write, notify, indicate)

  • Descriptor: Metadata about characteristics (for example, notification enable, format description)

Creating a GATT Server#

1. Add Services

  • Use rsi_ble_add_service() to add a service to the GATT database

  • Specify service UUID (16-bit SIG UUID or 128-bit custom UUID)

  • Service handle is returned for adding characteristics

2. Add Characteristics

  • Use rsi_ble_add_attribute() to add characteristics to a service

  • Specify characteristic UUID, properties (read, write, notify, indicate), and permissions

  • Characteristic handle is returned for value operations

3. Set Characteristic Values

  • When services are maintained in firmware: Use rsi_ble_set_local_att_value() to set and update characteristic values

  • Values can be updated at runtime as data changes

4. Handle Client Requests

  • Register GATT callbacks using rsi_ble_gatt_register_callbacks()

  • When services are maintained in firmware (default): The firmware automatically handles read/write responses

  • When services are maintained on the host (ATT_MAINTAIN_IN_HOST): Application must manually respond to requests

    • Handle read requests: rsi_ble_read_req_t (through rsi_ble_on_read_req_event_t callback) - respond with rsi_ble_gatt_read_response()

    • Handle write requests: rsi_ble_event_write_t (through rsi_ble_on_gatt_write_event_t callback) - respond with rsi_ble_gatt_write_response()

    • Handle prepare write: rsi_ble_event_prepare_write_t (through rsi_ble_on_gatt_prepare_write_event_t callback) - respond with rsi_ble_gatt_prepare_write_response()

    • Handle execute write: rsi_ble_execute_write_t (through rsi_ble_on_execute_write_event_t callback) - process queued writes

For request/response APIs (for example, rsi_ble_gatt_read_response(), rsi_ble_gatt_write_response(), rsi_ble_gatt_prepare_write_response()), see the BLE Server. For callback structures and event types (for example, rsi_ble_read_req_t, rsi_ble_on_execute_write_event_t), see Callbacks Declarations (bt-low-energy8).

GATT Server Management#

The following APIs are available for GATT server management. See the BLE Server for supported operations and limitations.

Removing Services:

  • Use rsi_ble_remove_gatt_service() to remove a service from the GATT database

  • Requires the service handle returned when the service was added

  • All characteristics and descriptors within the service are removed automatically

Removing Attributes:

  • Use rsi_ble_remove_gatt_attibute() to remove a specific attribute (characteristic or descriptor) from a service

  • Requires both the service handle and the attribute handle

Reading Local Attribute Values:

  • Use rsi_ble_get_local_att_value() to read the current value of a local attribute

  • Returns the attribute value in the response structure

Note: This API can only be used if the service is maintained inside the firmware (not in host)

Characteristic Properties#

Read Property:

  • Central device can read the characteristic value

  • When services are maintained in firmware: Read responses are handled automatically by firmware

  • When services are maintained on the host: Handle rsi_ble_read_req_t (through rsi_ble_on_read_req_event_t callback) and respond with rsi_ble_gatt_read_response()

Write Property:

  • Central device can write to the characteristic value

  • When services are maintained in firmware: Write responses are handled automatically by firmware

  • When services are maintained on the host: Handle rsi_ble_event_write_t and respond with rsi_ble_gatt_write_response()

Notify Property:

  • Peripheral can send notifications to central device

  • Central device enables notifications through Client Characteristic Configuration Descriptor (CCCD)

  • Use rsi_ble_notify_value() to send notification

Indicate Property:

  • Peripheral can send indications to central device (requires acknowledgment)

  • Central device enables indications through CCCD

  • Use rsi_ble_indicate_value() to send indication

  • Wait for confirmation callback (rsi_ble_on_event_indicate_confirmation_t) before sending next indication

  • Or use rsi_ble_indicate_value_sync() which automatically waits for confirmation

GATT Server Best Practices#

  • Service Organization: Group related characteristics into logical services

  • UUID Selection: Use 16-bit Bluetooth SIG UUIDs for standard services, 128-bit UUIDs for custom services

  • Value Updates:

    • When services are maintained in firmware: Update characteristic values using rsi_ble_set_local_att_value() when data changes

  • Error Handling: Respond to invalid requests with rsi_ble_att_error_response() using appropriate error codes

  • MTU Exchange: MTU exchange is driven by ATT roles (not GAP roles). As an ATT Server (GATT Server), respond to MTU exchange requests from the ATT Client using rsi_ble_mtu_exchange_resp() when RSI_BLE_MTU_EXCHANGE_FROM_HOST is enabled. Note: A device can be both ATT Client and ATT Server simultaneously.

Characteristic Notifications and Indications#

Notifications and indications allow the GATT server to push data to the GATT client without the client explicitly requesting it. This is essential for real-time data applications.

Notifications vs Indications#

Notifications:

  • Unacknowledged: No confirmation from central device

  • Lower Latency: Faster transmission, no waiting for acknowledgment

  • Use Case: High-frequency data updates where occasional loss is acceptable (for example, sensor readings)

  • API: rsi_ble_notify_value()

Indications:

  • Acknowledged: Central device must confirm receipt

  • Higher Reliability: Guaranteed delivery (within supervision timeout)

  • Use Case: Important data that must be received (for example, alerts, critical status)

  • API: rsi_ble_indicate_value() or rsi_ble_indicate_value_sync()

Enabling Notifications/Indications#

GATT server — notify and indicate characteristics:

Define the characteristic with notify and/or indicate in the GATT database (see Implementation Steps below), apply the correct update path for firmware- vs host-maintained services, then push updates after the central enables the CCCD (Client Characteristic Configuration Descriptor (CCCD) as mentioned below).

Client Characteristic Configuration Descriptor (CCCD):

  • Central device enables notifications/indications by writing to the CCCD

  • CCCD value: 0x0001 = notifications enabled, 0x0002 = indications enabled

  • Peripheral receives rsi_ble_event_write_t event when CCCD is written

  • Check the characteristic handle and value to determine if notifications/indications are enabled

Implementation Steps:

  1. Set the notify and/or indicate property bits in the property field of rsi_ble_req_add_att_s when calling rsi_ble_add_attribute().

  2. Firmware-maintained services (default): update the characteristic with rsi_ble_set_local_att_value() as in GATT Server Implementation.

  3. Host-maintained services (RSI_BLE_ATT_MAINTAIN_IN_HOST in RSI_BLE_ATT_CONFIG_BITMAP): the characteristic value is in application memory and can be updated from application code.

  4. Add the CCCD descriptor when creating the characteristic (explicitly as part of the attribute definition).

  5. Monitor CCCD writes through rsi_ble_event_write_t events.

  6. Track which characteristics have notifications/indications enabled.

  7. After the CCCD is enabled, use rsi_ble_notify_value() or rsi_ble_indicate_value() to push updates when data changes.

Note: For characteristic values larger than 20 bytes, Silicon Labs recommends host-maintained storage (RSI_BLE_ATT_MAINTAIN_IN_HOST, step 3). For firmware-maintained services, the WiSeConnect BLE API description for rsi_ble_set_local_att_value() documents attribute data size less than 20 bytes during service creation as a rule.

Sending Notifications#

Basic Notification:

// Send notification for a characteristic
rsi_ble_notify_value(remote_dev_addr, char_handle, data, data_len);

Notification Best Practices:

  • Check if notifications are enabled before sending

  • Use appropriate connection interval for data rate

  • Buffer management: Use rsi_ble_set_wo_resp_notify_buf_info() to configure buffer behavior

Sending Indications#

Basic Indication:

// Send indication (asynchronous)
rsi_ble_indicate_value(remote_dev_addr, char_handle, data, data_len);

// Or synchronous (wait for confirmation)
rsi_ble_indicate_value_sync(remote_dev_addr, char_handle, data, data_len);

Indication Flow:

  1. Send indication using rsi_ble_indicate_value()

  2. Wait for confirmation callback (rsi_ble_on_event_indicate_confirmation_t) before sending next indication

  3. Only send next indication after confirmation received

  4. Use rsi_ble_indicate_value_sync() for simplified synchronous operation (handles waiting automatically)

Indication Best Practices:

  • Always wait for confirmation before sending next indication

  • Implement timeout handling for missing confirmations

  • Use indications for critical data that must be delivered

  • Consider connection supervision timeout when waiting for confirmations


APIs Used in This Section#

Topic

APIs / symbols

Reference

GATT server — database

rsi_ble_add_service(), rsi_ble_add_attribute(), rsi_ble_set_local_att_value(), rsi_ble_get_local_att_value(), rsi_ble_remove_gatt_service(), rsi_ble_remove_gatt_attibute(); attribute request struct rsi_ble_req_add_att_s

BLE Server

GATT server — responses / ATT

rsi_ble_gatt_read_response(), rsi_ble_gatt_write_response(), rsi_ble_gatt_prepare_write_response(), rsi_ble_att_error_response(), rsi_ble_mtu_exchange_resp()

BLE Server, Synchronous Client

Host-maintained ATT — events / callbacks

rsi_ble_read_req_t, rsi_ble_on_read_req_event_t, rsi_ble_event_write_t, rsi_ble_on_gatt_write_event_t, rsi_ble_event_prepare_write_t, rsi_ble_on_gatt_prepare_write_event_t, rsi_ble_execute_write_t, rsi_ble_on_execute_write_event_t, rsi_ble_on_event_indicate_confirmation_t

Callbacks Declarations, Register Callbacks

Build / feature flags (prose)

RSI_BLE_ATT_MAINTAIN_IN_HOST, RSI_BLE_ATT_CONFIG_BITMAP, RSI_BLE_MTU_EXCHANGE_FROM_HOST

Developing with the WiSeConnect SDK, Overview

Notifications / indications

rsi_ble_notify_value(), rsi_ble_indicate_value(), rsi_ble_set_wo_resp_notify_buf_info()

BLE Server

Indications (synchronous)

rsi_ble_indicate_value_sync() — WiSeConnect documents this API on the Asynchronous Client page; it is used from the GATT server when sending indications

Asynchronous Client

Callbacks

rsi_ble_gatt_register_callbacks()

Register Callbacks