Different Value Types of Characteristics#


Introduction#

In general, BLE is used for wireless communication. Operations on characteristics are the way to achieve the communication.

Characteristics#

Characteristics are a concept of GATT Profile, which defines Client and Server roles. Server holds the state or data and client can request the state or data. Below is the definition of server and client from the Bluetooth SPEC.

Client is the device that initiates commands and requests towards the server and can receive responses, indications and notifications sent by the server.

Server is the device that accepts incoming commands and requests from the client and sends responses, indications and notifications to a client.

The GATT Profile specifies the structure in which profile data is exchanged. This structure defines basic elements such as services and characteristics, used in a profile.

Profile#

The top level of the hierarchy is a profile. A profile is composed of one or more services necessary to fulfill a use case. A service is composed of characteristics or references to other services. Each characteristic contains a value and may contain optional information about the value. The service and characteristic and the components of the characteristic (i.e., value and descriptors) contain the profile data and are stored in Attributes on the server.

Service#

A service is a collection of data and associated behaviors to accomplish a particular function or feature of a device or portions of a device. A service may include other primary or secondary services and/or a set of characteristics that make up the service. GATT also specifies the format of data contained on the GATT server. Attributes, as transported by the Attribute protocol, are formatted as Services and Characteristics. Services may contain a collection of characteristics. Characteristics contain a single value and any number of descriptors describing the characteristic value.

Characteristic#

A characteristic is a value used in a service along with properties and configuration information about how the value is accessed and information about how the value is displayed or represented. A characteristic definition contains a characteristic declaration, characteristic properties, and a value. It may also contain descriptors that describe the value or permit configuration of the server with respect to the characteristic value.

Figure 1. GATT-Based Profile hierarchyFigure 1. GATT-Based Profile hierarchy

Characteristic Value Types#

The above section introduces how to achieve communication among BLE devices. This section describes the differences among the types of a characteristic value. In the UG188: Blue Gecko Bluetooth Profile Toolkit Developer's Guide, 3 types of values can be used, hex, utf-8 and user. See chapter 2.5.3 for more information.

Available Types:

hex: The characteristic value is a hexadecimal value. In figure 2, the initialization value has the format of 0xXXXX, the characteristic value has the length of 2 bytes, and is initialized with the value 0x1122.

Figure 2. Hexadecimal TypeFigure 2. Hexadecimal Type

utf-8: The characteristic is a string and it takes a string as its initialization value. In figure 3, the characteristic has 10 bytes length and is initialized with the string value "Blue Gecko".

Figure 3. UTF-8 TypeFigure 3. UTF-8 Type

user: When the characteristic type is marked as type="user", the application has to initialize the characteristic value and also provide it when a read operation occurs, for example. The Bluetooth stack does not initialize the value nor automatically provide the value when it's being read. When this is set, the Bluetooth stack generates gatt_server_user_read_request or gatt_server_user_write_request, which must be handled by the application.

Default: utf-8

Comparison#

The type "hex" and "utf-8" are the same in terms of user operations, but are not of the same length. The section below, lists the differences between type "user" and "hex" to help users in choosing the right property of a characteristic value. The most significant difference between the type “user” and the other two types is where the data is stored.

Type – hex or utf-8#

If you use the property other than "user", the stack will allocate and maintain the buffer for the characteristic value automatically.

  • When a read request is received, the read response will be filled with the characteristic value and sent back to the peer device by the stack without user involvement.

  • When a write request is received, the stack will modify the characteristic value and send the write response to the peer device, then generate a gecko_evt_gatt_server_attribute_value_id event to inform users about the new value.

  • When sending notification/indication, the characteristic value has to be read from the stack, then the read value needs to be placed into the API gecko_cmd_gatt_server_send_characteristic_notification(...).

  • To read or write the characteristic value locally, use the below 2 APIs.

static inline struct gecko_msg_gatt_server_read_attribute_value_rsp_t*
gecko_cmd_gatt_server_read_attribute_value(uint16 attribute,
                                           uint16 offset);
static inline struct gecko_msg_gatt_server_write_attribute_value_rsp_t*
gecko_cmd_gatt_server_write_attribute_value(uint16 attribute,
                                            uint16 offset,
                                            uint8 value_len,
                                            const uint8* value_data);

Figure below show the flow of typical GATT operations when using hex characteristic value type.

Figure 4. Hex Type - GATT ReadFigure 4. Hex Type - GATT Read

Figure 5. Hex Type - GATT WriteFigure 5. Hex Type - GATT Write

Figure 6. Hex Type - GATT Notification/IndicationFigure 6. Hex Type - GATT Notification/Indication

Type – user#

If you use "user" as the value type, the value of the characteristic is stored in the application layer, which means the users should be responsible for allocating, maintaining, and freeing a suitable buffer for the characteristic value. Additionally, you need to respond to the GATT write/read requests by sending write/read response back to the peer device via below APIs.

static inline struct gecko_msg_gatt_server_send_user_read_response_rsp_t*
gecko_cmd_gatt_server_send_user_read_response(uint8 connection,
                                              uint16 characteristic,
                                              uint8 att_errorcode,
                                              uint8 value_len,
                                              const uint8* value_data);
static inline struct gecko_msg_gatt_server_send_user_write_response_rsp_t*
gecko_cmd_gatt_server_send_user_write_response(uint8 connection,
                                               uint16 characteristic,
                                               uint8 att_errorcode);

For example, if you have a characteristic with length 60, you need to allocate a 60-byte buffer in the application layer to store its value.

  • When a read request is received, gecko_evt_gatt_server_user_read_request_id event will be generated from the stack to the application and you need to respond the characteristic value via gecko_cmd_gatt_server_send_user_read_response(…)

  • When a write request is received, gecko_evt_gatt_server_user_write_request_id event is generated. At this point, users decide how to handle the value with the local buffer against the data in write request and respond it via gecko_cmd_gatt_server_send_user_write_response(…).

  • When sending notification/indication, the application buffer can be directly put into the API gecko_cmd_gatt_server_send_characteristic_notification(...).

Figures below show the flow of typical GATT operations when using hex characteristic value type.

Figure 7. User Type - GATT ReadFigure 7. User Type - GATT Read

Figure 8. User Type - GATT WriteFigure 8. User Type - GATT Write

Figure 9. User Type - GATT Notification/IndicationFigure 9. User Type - GATT Notification/Indication

Notes:

  1. DO NOT use the APIs gecko_cmd_gatt_server_read_attribute_value(...) and gecko_cmd_gatt_server_write_attribute_value(...) to read or write a characteristic value whose type is "user", because the data buffer is in your application code and stack will never know its value.

  2. DO NOT forget to respond to the read and write requests if the characteristic value type is “user”, otherwise no other GATT operation can be issued until GATT timeout - typically 30 seconds.

Conclusions and Suggestions#

Using "user" and using "hex"

  • Type hex/utf-8

    • Advantage – Stack will handle the read and write request to the characteristics, which is more effective and faster.

    • Disadvantage – Users can't access the characteristic buffer directly. Stack APIs are needed to read and write the value locally.

  • Type user

    • Advantage – The buffer storing the characteristic value is in the application layer, which means it’s easier to read and modify the value.

    • Disadvantage – Users must respond to the read and write requests by calling stack APIs. If users don’t respond, no other GATT operation can be issued until GATT timeout. Because every GATT operation requires involving the application, it could be less effective and consume more power. Additionally, long-write, reliable-write and read-multiple-values requests are NOT supported if a characteristic is user type.

Code Example#

This guide has a related code example, here: Different Characteristic Value Type Example.