General Steps

[中文]

Note

This document is automatically translated using AI. Please excuse any detailed errors. The official English version is still in progress.

This document summarizes the common implementation process of BLE in ESP-IDF, covering key system and Bluetooth initialization, GAP and GATT configuration, service and feature registration, broadcasting and scanning, connection management and event handling, etc. The document lists the basic knowledge of each stage, the involved APIs and the calling order, providing a unified implementation reference for different BLE examples. The content of the document is only based on Bluedroid implementation and does not involve NimBLE.

Mastering the content of this document can help to quickly understand the core process of BLE, reuse common code in different applications, and efficiently locate mode differences and specific implementations in combination with example documents.

Broadcasting and Scanning

Broadcasting and Scanning Parameters

The discovery and visibility of BLE devices are controlled by broadcast parameters and scan parameters, which are used for GATT Server broadcasting and GATT Client scanning respectively. Reasonable configuration of these parameters can balance the speed of device discovery, connection response, and power consumption.

  1. Broadcast Parameters: Broadcast parameters are a set of settings used by the BLE Server to control broadcasting behavior during the broadcasting process, mainly including:

  • Transmission Interval: Controls the frequency of broadcast packet transmission, affecting the response speed and power consumption of device scanning or connection.

  • Broadcast Behavior: Determines whether the device can be connected or scanned.

  • Broadcast Address: The address type (public address or random address) used by the local device during broadcasting, as well as the address of the target device.

  • Broadcast Channel: Selects the physical channel (37, 38, 39) used for sending broadcast packets.

  • Filter Policy: Controls which devices can scan or connect to this device.

In ESP-IDF, you can set broadcast parameters by defining the esp_ble_adv_params_t structure, where members related to the target device address only need to be configured during directed broadcasting.

Its structure members are as follows:

  • adv_int_min: Minimum broadcast interval. The data type is uint16_t.

  • adv_int_max: Maximum broadcast interval. The data type is uint16_t.

    Broadcast Interval

    Value Range

    Default Value

    0x0020 to 0x4000

    0x0800 corresponds to 1.28 seconds

Note

The steps to convert the interval and time are as follows:

  • Convert hexadecimal 0x0800 to decimal, which is 2048.

  • The unit of BLE broadcast interval is 0.625 ms, multiply by 0.625 ms to get the number of milliseconds: 2048 × 0.625 = 1280 ms

  • Convert to seconds: 1280 ÷ 1000 = 1.28 seconds

  • adv_type: Broadcast type. The data type is esp_ble_adv_type_t.

    esp_ble_adv_type_t

    Broadcast Type

    Description

    ADV_TYPE_IND

    Normal broadcast that can be scanned and connected

    ADV_TYPE_DIRECT_IND_HIGH

    High-speed connectable directed broadcast

    ADV_TYPE_SCAN_IND

    Broadcast that can be scanned but not connected

    ADV_TYPE_NONCONN_IND

    Broadcast that cannot be scanned or connected

    ADV_TYPE_DIRECT_IND_LOW

    Low-speed connectable directed broadcast

  • own_addr_type: The type of Bluetooth address used by the local device during broadcasting or scanning. The data type is esp_ble_addr_type_t.

    esp_ble_addr_type_t

    Address Type

    Description

    BLE_ADDR_TYPE_PUBLIC

    Public address

    BLE_ADDR_TYPE_RANDOM

    Random address

    BLE_ADDR_TYPE_RPA_PUBLIC

    Resolvable Private Address (RPA), generated based on public identity address

    BLE_ADDR_TYPE_RPA_RANDOM

    Resolvable Private Address (RPA), generated based on random identity address

  • peer_addr: The Bluetooth address used by the target device during broadcasting or scanning. The data type is esp_bd_addr_t, which is essentially a 6-byte array used to store the MAC address of the Bluetooth device. It needs to be obtained through a scan callback or manually assigned a specific address.

  • peer_addr_type: The type of Bluetooth address used by the target device during broadcasting or scanning. The data type is esp_ble_addr_type_t. But it only supports public addresses and random addresses.

  • channel_map: Broadcast channel. The data type is esp_ble_adv_channel_t.

    esp_ble_adv_channel_t

    Channel Selection

    Description

    ADV_CHNL_37

    Select channel 37 for broadcasting

    ADV_CHNL_38

    Select channel 38 for broadcasting

    ADV_CHNL_39

    Select channel 39 for broadcasting

    ADV_CHNL_ALL

    Select all three channels for broadcasting

  • adv_filter_policy: Broadcast filter policy. The data type is esp_ble_adv_filter_t.

    esp_ble_adv_filter_t

    Filter Policy

    Description

    ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY

    Allow scan and connection requests from all devices

    ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY

    Only allow scan requests from whitelisted devices, connection requests allow all devices

    ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST

    Scan requests allow all devices, connection requests only allow whitelist devices

    ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST

    Enumeration end value, used for advertisement filtering policy value check

  1. Scan Parameters: Scan parameters are a set of settings used by the BLE Client to control scanning behavior when scanning surrounding devices, mainly including:

  • Scan Type: Determines whether the scanner sends a scan request to the scannable broadcaster after receiving the broadcast packet.

  • Scan Window and Scan Interval: The scan interval controls the scan frequency, affecting the speed and power consumption of device discovery. The scan window represents the actual scan time length within each scan cycle, determining the active time of scanning.

  • Scan Address Type: The address type (public address or random address) used by the local device during scanning.

  • Scan Repeat Filter: Controls whether the link layer reports each advertisement packet to the host.

  • Scan Filter Policy: Determines whether the scan result only receives specific devices or all devices.

In ESP-IDF, the scan parameters can be set by defining the esp_ble_scan_params_t structure.

Its structure members are as follows:

  • scan_type: Scan type. The data type is esp_ble_scan_type_t.

    esp_ble_scan_type_t

    Scan Type

    Description

    BLE_SCAN_TYPE_PASSIVE

    Passive Scan

    BLE_SCAN_TYPE_ACTIVE

    Active Scan

  • own_addr_type: The Bluetooth address type used by the local device during broadcasting or scanning. The data type is esp_ble_addr_type_t.

  • scan_filter_policy: Scan filter policy. The data type is esp_ble_scan_filter_t.

    esp_ble_adv_filter_t

    Filter Policy

    Description

    BLE_SCAN_FILTER_ALLOW_ALL

    Accept all broadcast packets except undirected and not targeted at this device (default)

    BLE_SCAN_FILTER_ALLOW_ONLY_WLST

    Only accept broadcast packets from devices in the whitelist

    BLE_SCAN_FILTER_ALLOW_UND_RPA_DIR

    Accept all undirected broadcast packets, initiator address is resolvable private address directed broadcast packets, and directed broadcast packets for this device

    BLE_SCAN_FILTER_ALLOW_WLIST_RPA_DIR

    Accept all broadcast packets from devices in the whitelist, initiator address is resolvable private address directed broadcast packets, and directed broadcast packets for this device

  • scan_interval: Scan interval, i.e., scan frequency. The data type is uint16_t.

  • scan_window: Scan window, i.e., the actual scan duration within each scan cycle. The data type is uint16_t.

    Scan interval and window

    Value range

    Default value

    0x0004 to 0x4000

    0x0010 corresponds to 10 milliseconds

Note

The steps to set the interval and time conversion are as follows:

  • Convert hexadecimal 0x0800 to decimal, which is 2048.

  • The unit of BLE broadcast interval is 0.625 ms, multiply by 0.625 ms to get the number of milliseconds: 2048 × 0.625 = 1280 ms

  • Convert to seconds: 1280 ÷ 1000 = 1.28 seconds

  • scan_duplicate: Determines whether to generate a broadcast report for each received broadcast packet. The data type is esp_ble_scan_duplicate_t.

    esp_ble_scan_duplicate_t

    Scan duplicate filter

    Description

    BLE_SCAN_DUPLICATE_DISABLE

    Generate a broadcast report for each received broadcast packet

    BLE_SCAN_DUPLICATE_ENABLE

    Filter duplicate broadcast reports

    BLE_SCAN_DUPLICATE_ENABLE_RESET

    Enable duplicate filtering, reset each scan cycle, only supported in BLE 5.0

    BLE_SCAN_DUPLICATE_MAX

    Reserved for future use

Broadcast flags

The broadcast flag is a standard field of the BLE broadcast packet. The scanning end can quickly judge whether the target device supports connection, whether it is a BLE device, and whether it supports dual mode (BR/EDR and LE) through this flag.

Only one discovery mode flag (limited discoverable or generally discoverable) is allowed in the same broadcast packet, otherwise it will cause protocol stack parsing conflicts. In addition, choosing the dual mode support flag (DMT) does not mean that the device will definitely work in dual mode, and it also needs to be combined with hardware and protocol stack configuration.

The following are macro definitions provided by ESP-IDF, which can be used directly and configured by bitwise OR (|):

  • ESP_BLE_ADV_FLAG_LIMIT_DISC: General limited discoverable mode, indicating that the device can be discovered within a limited time, commonly used to reduce power consumption.

  • ESP_BLE_ADV_FLAG_GEN_DISC: General discoverable mode, indicating that the device can be continuously discovered, suitable for long-term connectable devices.

  • ESP_BLE_ADV_FLAG_BREDR_NOT_SPT: Does not support BR/EDR (classic Bluetooth), only supports BLE mode.

  • ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT: The controller supports dual mode.

  • ESP_BLE_ADV_FLAG_DMT_HOST_SPT: The host protocol stack supports dual mode.

  • ESP_BLE_ADV_FLAG_NON_LIMIT_DISC: Non-limited discoverable mode, indicating that no discovery mode related flags are set.

Common configurations:

  • ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT: Can be continuously discovered and only supports BLE mode.

Broadcast packets

A complete broadcast packet consists of several parts, for more details, see Broadcast Packet Structure. When actually writing code, you only need to write the broadcast data and scan response data parts, both of which have the same structure.

When configuring broadcast data, you can choose to use the raw broadcast packet or configure it using the structure esp_ble_adv_data_t.

  1. Using Raw Broadcast Packet: When using a raw broadcast packet, you need to understand the concept of each field (length, type, content) and arrange them according to the protocol format. ESP-IDF encapsulation types can simplify operations, but the core is still to correctly package each byte.

  • A raw broadcast packet is a byte array manually packaged according to the BLE broadcast protocol format, with each field arranged by byte.

  • Each broadcast data entry, i.e., field, consists of three parts, and the byte order must strictly comply with the BLE protocol specification to ensure that other BLE devices can correctly parse it.

Broadcast Data Structure

Serial Number

Name

Number of Bytes

Description

1

Data Length (AD Length)

1

The number of bytes occupied by the current field, excluding its own byte

2

Data Type (AD Type)

n

Identifies the field type, such as Flags, Service UUID, Device Name, etc., usually occupies 1 byte

3

Data (AD Data)

(AD Length - n)

The actual information carried by the field, such as the specific device name or service UUID

  • For common data types (such as Flags, TX Power, Service UUID, Device Name), ESP-IDF provides macro definitions that can be used directly, avoiding manual calculation or filling in each byte. All encapsulation types can be viewed at esp_ble_adv_data_type.

  1. Configuration through Structure: When configuring through a structure, users only need to focus on “what content to put”, and ESP-IDF will help you handle the protocol format of “how to put”, avoiding the complexity of manually packaging bytes.

  • ESP-IDF provides the structure esp_ble_adv_data_t, just fill in each field, and the BLE protocol stack will automatically package it into a byte array that conforms to the broadcast protocol format.

Structure Members

Structure Member

Description

Configuration

set_scan_rsp

Select whether the currently configured data is for scan response data or broadcast data.

true means it is used as scan response data, false means it is used as broadcast data.

include_name

Whether to include the device name in the broadcast data.

true means to include, false means not to include.

include_txpower

Whether to include TX power, used to indicate the size of the device’s transmission power.

true means to include, false means not to include.

min_interval

The device’s recommended minimum connection interval, connection time = min_interval × 1.25 ms.

The address range is 0x0006–0x0C80, 0xFFFF means unspecified.

max_interval

The maximum connection interval suggested by the device, where connection time = max_interval × 1.25 ms.

Must be greater than or equal to min_interval, 0xFFFF indicates unspecified.

appearance

The type of device appearance, such as heart rate monitors, keyboards, etc., used to identify the device category.

Uses a 16-bit integer value defined by Bluetooth SIG, such as 0x0340 for a heart rate monitor.

manufacturer_len

The length of manufacturer-specific data.

Obtained by calling sizeof(), the value must not exceed the total length of BLE broadcast data (31 bytes) minus the length of other occupied fields; when configured to 0, it means that the manufacturer-specific data is not included in the broadcast data, and p_manufacturer_data should be set to NULL.

p_manufacturer_data

Pointer to the manufacturer-specific data.

When the device needs to send manufacturer-specific information in the broadcast, such as hardware version number, device serial number, private protocol identifier, or specific status information, a custom byte array can be passed in, otherwise pass in NULL and set manufacturer_len to 0.

service_data_len

The length of service data, used for broadcasting specific service information.

Obtained by calling sizeof(), the value must not exceed the total length of BLE broadcast data (31 bytes) minus the length of other occupied fields; when configured to 0, it means that the service-related data is not included in the broadcast data, and p_service_data should be set to NULL.

p_service_data

Pointer to the service data.

When the device needs to send specific service-related information in the broadcast, such as current sensor readings, service version number, service-specific identifiers, or initial configuration information, a custom byte array can be passed in; otherwise, pass in NULL and set service_data_len to 0.

service_uuid_len

The length of the service UUID array being broadcast.

Filled in according to the number of services being broadcast, can be obtained by calling sizeof().

p_service_uuid

Pointer to the service UUID array, used to inform the scanning device of the type of service currently being broadcast.

Can use standard 16-bit UUID or custom 16/128-bit UUID.

flag

Broadcast flag, used to indicate the current device’s discoverable mode and supported protocol types.

ESP-IDF provides corresponding macro definitions, which users can directly use and combine by bitwise OR (|).

GATT

GATT Data Operations

GATT data operations refer to accessing characteristic data on the GATT server, including operations initiated by the client and the server. For detailed content and examples of GATT data operations, refer to the original document GATT Data Operations.

In addition to the read, write, and write (no response) operations mentioned in the original document, GATT also supports Prepare Write operations, which are used to write longer data to the server or perform packetized writing to ensure the consistency and reliability of the write transaction.

In the Prepare Write operation:

  • Client:

    1. The data to be written is divided into multiple segments, and the Prepare Write Request is sent in sequence. Each segment includes the characteristic handle, data segment, and offset (indicating the position of this segment in the entire data).

    2. After sending all fragments, initiate an Execute Write Request to notify the server to write all previously cached fragment data into the characteristic value at once, thus completing the entire write transaction.

  • Server:

    1. Cache the received fragments into a temporary buffer and return a Prepare Write Response to confirm that the fragment has been received.

    2. Upon receiving the client’s Execute Write Request, write all cached data into the characteristic value at once to achieve a complete write.

Therefore, in actual programming, if a device needs to act as a server to receive fragment data, a dedicated buffer needs to be created for “prepare write” to store the received fragment data, so that it can be written into the characteristic value at once after receiving the Execute Write Request.

Managing GATT Profile Information and Status

The GATT Profile instance structure is used to centrally manage GATT layer information, including callback functions, interface IDs, services, characteristics, and descriptors, etc. It is applicable to both Server and Client examples; where the Server focuses on local attributes and access permissions, and the Client focuses on the discovery and operation of remote services, to ensure correctness and efficient access in multi-Profile, multi-connection scenarios.

  1. GATT Server Profile Instance Structure

In the Server example, the gatts_profile_inst structure is mainly used to manage local services, characteristics, and descriptor information, as well as callback functions and connection status. Its structure members are as follows:

gatts_profile_inst

GATT Level

Structure Member

Description

Profile

gatts_cb

GATT Server callback function, used to bind the Profile with event handling logic, facilitating the handling of all client request events under this Profile.

gatts_if

GATT interface ID, used to identify this Profile, distinguishing different Profiles or GATT interfaces.

app_id

Application ID, used to identify the application to which this Profile belongs, distinguishing different instances when registering multiple Profiles.

conn_id

Connection ID, used to distinguish different client connections.

Service

service_handle

Service handle, used for subsequent operations to access this service.

service_id

Service identifier, including service UUID and primary/secondary service information.

Characteristic

char_handle

Characteristic handle, used for subsequent operations to access this characteristic value.

char_uuid

Characteristic UUID, convenient for clients to identify characteristics.

perm

Characteristic permissions, such as readable, writable, etc., determining the client’s access mode to the characteristic.

property

Characteristic properties, specified by the program to support operations such as read, write, notify, indicate.

Descriptor

descr_handle

Descriptor handle, used for subsequent operations to access this descriptor.

descr_uuid

Descriptor UUID, commonly used to identify descriptors such as CCCD.

  1. GATT Client Profile Instance Structure

The gattc_profile_inst structure in the Client example is mainly used to manage operations on the remote device’s services, characteristics, and descriptors, as well as connection status and callback logic. Its main members are as follows:

gattc_profile_inst

GATT Level

Structure Member

Description

Profile

gatts_cb

GATT Server callback function, binding Profile with event handling logic, used to handle all client request events under this Profile.

gatts_if

GATT interface ID, identifying this Profile, used to distinguish different Profiles or GATT interfaces.

app_id

Application ID, used to identify the application to which this Profile belongs, distinguishing different instances when registering multiple Profiles.

conn_id

Connection ID, used to distinguish different client connections.

remote_bda

Remote device Bluetooth address, used to identify the connection target.

Service

service_start_handle

Remote service start handle, used to identify the start position of the service in subsequent operations.

service_end_handle

Remote service end handle, used to identify the end position of the service in subsequent operations.

Characteristic

char_handle

Characteristic handle, used for subsequent operations to access this characteristic value.

Most of the members in the structure are generated or allocated by the protocol stack at runtime, and are returned by the protocol stack when registering services or characteristics. When defining the structure, you only need to pre-declare these members, and you can use default values or 0 for initialization. The actual values are assigned to the structure in the callbacks of registering services, characteristics, or descriptors.

The above Profile instance structure has strong universality and is suitable for most GATT Server and Client examples and application scenarios, because each Profile needs to manage callbacks, interface IDs, services, characteristics, and descriptors, etc. Only under special requirements do you need to modify or extend the structure members, for example:

  • Multiple characteristics or descriptors management: You need to modify the corresponding handle and UUID variables to arrays or linked lists to save the information of multiple characteristics or descriptors.

  • Cache or status flag: You need to add structure members to write long data into the buffer, notify status, or custom status flags.

  • Multiple clients or complex logic: You need to add structure members to save connection context information, event queues, or timer pointers.

  • Client special requirements: You may need to save the discovery results of remote services, characteristic element arrays, or descriptor element array pointers for quick search and operation of target services or characteristics.

GATT Attribute Table

The GATT Attribute Table is a set of “Attributes” arranged in order. Each attribute represents a data item that can be discovered/read and written by the client. All services, characteristics, and their descriptors are stored in this table in the form of “attributes”, uniquely identified by the protocol stack allocating handles.

An attribute consists of 5 parts:

  • Handle: A one-time incrementing number allocated by the protocol stack at runtime, used to uniquely identify and access this attribute. They need to be stored in a handle_table for use in event callbacks.

  • Declaration UUID: The unique identifier of the attribute, which can be a 16-bit, 32-bit, or 128-bit UUID, determining the specific purpose and meaning of this attribute.

  • Permissions: Define the client’s access rights to this attribute, such as readable, writable, requiring encryption, requiring authentication, etc.

  • Value: The actual data carried by the attribute or the pointer to the data, including the maximum number of bytes allowed for the attribute value and the number of bytes currently actually stored by the attribute.

  • Type: Attribute type, used to describe the role of this attribute in the GATT layer.

    • Primary Service Declaration: Used to define a complete set of features, such as heart rate service, device information service.

    • Secondary Service Declaration: An optional item, with the same structure as the primary service, but usually included by other services and not directly exposed.

    • Include Declaration: An optional item, used to reference the definition of another service in the current service. The included service allows the reuse of existing service functions without having to redefine related characteristics.

    • Characteristic Declaration: Used to describe the metadata of a characteristic, including properties, the handle of the characteristic value, and the UUID of the characteristic. The handle of the characteristic value is the number of the characteristic value in the GATT database, different from the declaration handle of the characteristic itself.

    • Characteristic Value: Stores the actual data content of the characteristic, such as heart rate value or temperature reading.

    • Characteristic Descriptors: An optional item, used to further describe the properties of the characteristic.

      • Client Characteristic Configuration (CCC/CCCD): Used to allow the client to control whether a characteristic is enabled.

      • Characteristic User Description (CUD): A user-readable description of the characteristic, i.e., a text explaining the purpose of the characteristic in natural language, such as “device serial number” or “battery level percentage”, convenient for direct display by the client.

      • Characteristic Presentation Format (CPF): The format of the value (unit, resolution, etc.).

      • Characteristic Extended Properties (CEP): Extended properties.

The steps to define the attribute table in ESP-IDF are as follows:

  1. Define attribute index: Use enumeration to define all attribute entries and the total number of attributes, and then access the handle of the corresponding attribute through the index to avoid using magic numbers in the code.

Note

“Magic numbers” usually refer to numeric constants written directly in the code without explanatory meaning.

  1. Create attribute array: Define an array of type esp_gatts_attr_db_t, the length of the array equals the total number of attributes, and each element of the array corresponds to an attribute entry.

  2. Arrange attribute order: Each element in the array represents an attribute. The typical attribute order is: Service declaration > (Characteristic A: declaration > value > descriptor) > (Characteristic B: declaration > value > descriptor), the handle of each entry is created and returned by the stack.

  3. Configure attribute fields: The fields that need to be configured for each attribute entry are as follows:

  • Attribute response control field: Specifies who is responsible for responding when the attribute is read and written by the client. The data type is esp_attr_control_t, see GATT API <https://docs.espressif.com/projects/esp-idf/en/v5.4.2/esp32/api-reference/bluetooth/esp_gatt_defs.html#_CPPv415esp_attr_desc_t>.

Optional value

Description

ESP_GATT_AUTO_RSP

The protocol stack automatically generates a response, no need for the user to manually handle, suitable for static, simple attribute values.

ESP_GATT_RSP_BY_APP

The application program constructs and sends the response in the callback function, suitable for dynamically generated or permission-judged attribute values.

  • Attribute Metadata Field: Describes the attribute type and access control. The data type is esp_attr_desc_t, see GATT API.

    • Length of attribute type UUID: If it is a standard GATT type (such as Primary Service), use a 16-bit UUID; if it is a custom service or feature, usually use a 128-bit UUID to avoid conflicts.

    Optional Value

    Description

    ESP_UUID_LEN_16

    UUID length is 2 bytes

    ESP_UUID_LEN_32

    UUID length is 4 bytes

    ESP_UUID_LEN_128

    UUID length is 16 bytes

    • UUID pointer: Points to the UUID data of this attribute type. 16, 32, or 128-bit data must be forcibly converted to uint8_t* to uniformly handle byte arrays.

    • Access permissions: For Service declarations, permissions are generally only set to readable.

    Optional Value

    Description

    ESP_GATT_PERM_READ

    Read-only

    ESP_GATT_PERM_WRITE

    Write-only

    ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE

    Readable and writable

    ESP_GATT_PERM_READ_ENCRYPTED

    The attribute can be read, but it must be read under an encrypted connection, i.e., BLE link encryption is required.

    ESP_GATT_PERM_WRITE_ENCRYPTED

    The attribute can be written, but it must be written under an encrypted connection to ensure data transmission security.

    • The maximum length of this attribute value: The upper limit to which this attribute value can be extended.

    • The current length of this attribute value: The data length that has been occupied at initialization.

    Attribute Type

    Attribute Value Content

    Maximum Length

    Current Length

    Service Declaration

    Service UUID

    Length of Service UUID

    Equal to the maximum length

    Characteristic Declaration

    Characteristic properties (such as read, write, notify, etc.)

    1 byte

    Equal to the maximum length

    Characteristic Value

    Custom data

    Custom length, can be set according to needs

    The data length written at initialization, can be less than or equal to the maximum length

    Service Declaration

    Determined by the descriptor type (such as CCCD, user-defined descriptor)

    Determined by the descriptor type

    Initialization value length, fixed descriptors are usually equal to the maximum length, variable descriptors may be less than the maximum length

    • Initial value pointer: Points to the initial data of this attribute, which can be a constant array or dynamically allocated memory.

GATT Event Callback Function

In both the GATT Server and GATT Client examples, event callback functions are defined to receive and process events reported by the BLE protocol stack, serving as a bridge between the protocol stack and the application layer. Both are highly consistent in form: they are registered by the ESP-IDF framework, serving as the unified interface between the GATT layer and the user application. Then, within the function, the corresponding user logic is called based on the event type, implementing event distribution and processing.

  • The Server callback function mainly handles passive response events, which are often related to the local attribute table, such as the registration of services and characteristics, the processing of client read and write requests, and the sending of notifications and indications. The focus is on how to provide and maintain local GATT services.

  • The Client callback function is used to initiate operations and process results. The events handled mainly involve the discovery of remote services, the reading and writing of characteristics and descriptors, and the subscription and reception of notifications or indications. The focus is on how to operate and manage remote device resources.

The event callback functions in the examples are all of the static type and have no return value. They are used to process and distribute GATT events. The parameter passing form is as follows:

Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

event

Event type.

Different processing can be performed in the callback based on the event type.

gatts_if

GATT server access interface.

Assigned by the protocol stack, used to distinguish different GATT Profile service instances, and identify the corresponding Profile in the event callback.

param

Pointer to the structure of the event parameters, containing detailed information about the event.

Different events correspond to different union members, such as broadcast data, scan results, connection information, etc.

The function can be divided into two stages:

  1. Event registration processing:

  • When the event type is registration completion, check whether the registration is successful.

  • If the registration is successful, store the interface identifier gatts_if assigned by the protocol stack in the Profile table for subsequent event identification; if the registration fails, print an error log and terminate the distribution.

  1. Event distribution:

  • If the input interface identifier gatts_if does not specify an interface (ESP_GATT_IF_NONE), the event will be broadcast to all Profiles, allowing each Profile to determine whether to process it.

  • If the interface identifier is specified, the event is only distributed to the matching Profile, preventing unrelated Profiles from receiving it.

  • The distributed events cover the complete interaction of the GATT protocol layer:

    • The Server side handles service registration, read and write requests, notification sending, etc.

    • The Client side handles service discovery, characteristic access, notification subscription, etc.

  • Each Profile callback function determines whether to respond to the event through gatts_if and event, implementing the logical isolation and management of multiple Profiles.

Client Characteristic Configuration Descriptor (CCCD)

  • CCCD (Client Characteristic Configuration Descriptor) is a standard descriptor stipulated by the GATT protocol, used to store the client’s subscription status for a certain characteristic.

  • CCC (Client Characteristic Configuration) refers to the content in the standard descriptor, that is, the value saved in the CCCD.

The client controls the server’s notification and indication functions of the characteristic by writing into the CCC:

  • Notification: The server sends data to the client, but does not wait for confirmation; the client can directly process the data after receiving it, without feedback to the server.

  • Indication: The server sends data and waits for the client to confirm; the client must reply to confirm after receiving the data, and the server considers the sending successful only after receiving the confirmation.

When the server receives the CCC written by the client, it determines the operation to be performed based on the written value:

  • 0x0001: Enable notification, the server constructs the data to be sent, and calls esp_ble_gatts_send_indicate() to send the notification to the client.

  • 0x0002: Enable indication, the server constructs the data to be sent, and calls esp_ble_gatts_send_indicate() to send the indication to the client. The client needs to return an ACK for confirmation, ensuring reliable data arrival.

  • 0x0000: Disable notifications and indications. Stop sending notifications and indications for this characteristic, the server no longer actively pushes data to the client

  • Other values: Print unknown descriptor error.

When calling esp_ble_gatts_send_indicate() to send characteristic data to a specified client, you need to pass in the server instance, connection ID, characteristic handle, data content, and whether the client needs to confirm. For more parameter descriptions, please refer to GATT Server API.

Main Function Description

Non-Volatile Storage (NVS)

  1. Initialize Non-Volatile Storage:

  • Non-volatile storage is a key module in the device used to store persistent data, which remains after power off.

  • Call nvs_flash_init() to initialize NVS, complete the preparation and mounting of the storage medium. For related parameter descriptions, please refer to Non-Volatile Storage Library API.

  1. Check the return value:

  • Timely discover possible problems during the initialization process, such as NVS partition is full or version mismatch, to avoid errors in subsequent data reading and writing, leading to functional abnormalities or even crashes.

  • If an exception is returned, call nvs_flash_erase() to erase the NVS partition. For related parameter descriptions, please refer to Non-Volatile Storage Library API.

    • ESP_ERR_NVS_NO_FREE_PAGES: Indicates that the NVS partition is full, there are no available free pages, and new data cannot be written.

    • ESP_ERR_NVS_NEW_VERSION_FOUND: Indicates that the data version of the current NVS partition does not match the version expected by the library, and it may be necessary to upgrade or format the partition.

  • After erasing the partition, you need to call the initialization function again and check the return value again to ensure successful initialization.

Release Bluetooth Memory

  • At system startup, a portion of the memory pool is reserved for “full-featured Bluetooth” (BR/EDR + BLE).

  • In actual use, you need to release unnecessary memory according to your needs to avoid waste.

Note

You must release it before calling esp_bt_controller_init() to initialize the Bluetooth controller, otherwise the memory partition will be fixed and cannot be released.

Create/Initialize Bluetooth Controller

  • Configure the Bluetooth controller parameters through the esp_bt_controller_config_t structure, usually use BT_CONTROLLER_INIT_CONFIG_DEFAULT() to quickly load the default configuration.

  • The configuration covers task scheduling, memory buffering, low-power mode, RF parameters, and protocol security features, etc., ensuring the performance, compatibility, and stability of the Bluetooth controller during initialization. For specific structure members, refer to Controller API.

  • Initialize the Bluetooth controller, start internal tasks and resources.

Start Bluetooth Controller

  • Start the initialized Bluetooth controller and set its mode.

Initialize/Enable Protocol Stack

  • Initialize the Bluedroid protocol stack.

  • Enable the Bluedroid protocol stack to make it operational.

Register Callback Function

  • Register callback functions to handle different events.

  • Register the corresponding function for the GATT Server callback function to handle read/write, connection, disconnection, and other events.

  • Register the corresponding function for the GAP callback function to handle broadcasting and scanning events.

Register GATT Application

  • Register GATT application, integrate user-defined service logic into the protocol stack, and get event callback channels.

  • After registration, the protocol stack will trigger the ESP_GATTS_REG_EVT event.

Set Local GATT MTU (Maximum Transmission Unit)

  • Set the size of the local GATT MTU.

  • After registration, it will trigger the ESP_GATTS_MTU_EVT event.

Note

MTU determines the maximum amount of data that can be transmitted at once, default is 23 bytes, and can be adjusted as needed.

API Summary

Bluetooth Controller Initialization and Enablement

  1. esp_bt_controller_init(): Used to initialize the Bluetooth controller to allocate tasks and other resources. Refer to Controller API.

Parameter Explanation

Input Parameter

Parameter Description

cfg

Initial Bluetooth controller configuration.

  1. esp_bt_controller_enable(): Used to enable the Bluetooth controller. Refer to Controller API.

Parameter Explanation

Input Parameter

Parameter Description

mode

The Bluetooth controller mode to be enabled.

  1. esp_bluedroid_init(): Used to initialize and allocate resources required by Bluetooth. Refer to Bluetooth API.

  1. esp_bluedroid_enable(): Used to enable Bluetooth. Refer to Bluetooth API.

  1. esp_bt_controller_mem_release: Used to release the controller memory of a specified mode. Refer to Controller API.

Parameter Explanation

Input Parameter

Parameter Description

mode

The Bluetooth controller mode whose memory is to be released.

GATT Service Registration and Operation

  1. esp_ble_gatts_register_callback(): Used to register the GATT server application callback function. Refer to GATT Server API.

Parameter Explanation

Input Parameter

Parameter Description

callback

Pointer to the application callback function.

  1. esp_ble_gatts_app_register(): Used to register the GATT server application. Refer to GATT Server API.

Parameter Explanation

Input Parameter

Parameter Description

app_id

UUID of different applications.

  1. esp_ble_gatts_create_attr_tab(): Used to create an attribute table. Refer to GATT Server API.

Parameter Explanation

Input Parameter

Parameter Description

gatts_attr_db

Pointer to the service attribute table.

gatts_if

GATT server access interface

max_nb_attr

The number of attributes to be added to the service database.

srvc_inst_id

Service instance ID.

  1. esp_ble_gatts_start_service(): Used to start the service. Refer to GATT Server API.

Parameter Explanation

Input Parameter

Parameter Description

service_handle

The target service handle to be started.

  1. esp_ble_gatts_send_response(): Used to send a write response to the client. Refer to GATT Server API.

Parameter Explanation

Input Parameter

Parameter Description

gatts_if

GATT server access interface.

conn_id

Connection ID.

trans_id

Transmission ID.

status

Response status.

rsp

Pointer to the response data.

  1. esp_ble_gatt_set_local_mtu(): Used to set the size of the local MTU, which needs to be called before establishing a BLE connection.

Parameter Explanation

Input Parameter

Parameter Description

mtu

The desired size of the MTU.

  1. esp_ble_gattc_enh_open(): Used to create an ACL connection. Refer to GATT Client API.

Parameter Explanation

Input Parameter

Parameter Description

gattc_if

GATT client access interface.

esp_gatt_create_conn

Pointer to the structure containing the connection parameters.

Note

ACL (Asynchronous Connectionless) connection is a basic data link connection type in Bluetooth, used for data transmission between two devices.

  1. esp_ble_gattc_send_mtu_req(): Used to configure the MTU size of the GATT channel. Refer to GATT Client API.

Parameter Explanation

Input Parameter

Parameter Description

gattc_if

GATT client access interface.

conn_id

Connection ID.

  1. esp_ble_gattc_search_service(): Used to search for services from the local GATTC cache. Refer to GATT Client API.

Parameter Explanation

Input Parameter

Parameter Description

gattc_if

GATT client access interface.

conn_id

Connection ID.

filter_uuid

UUID of the target service. If NULL is passed in, all services are returned.

  1. esp_ble_gattc_get_attr_count(): Used to get the number of specified services or characteristics in the local GATTC cache. Refer to GATT Client API.

Parameter Explanation

Input Parameters

Parameter Description

gattc_if

GATT client access interface.

conn_id

Connection ID.

type

Attribute type.

start_handle

Attribute start handle.

end_handle

Attribute end handle.

char_handle

Characteristic handle.

count

The number of specified attribute types found in the local GATTC cache.

  1. esp_ble_gattc_get_char_by_uuid(): Used to get the characteristic of the specified characteristic UUID in the local GATTC cache. Refer to GATT Client API.

Parameter Explanation

Input Parameters

Parameter Description

gattc_if

GATT client access interface.

conn_id

Connection ID.

start_handle

Attribute start handle.

end_handle

Attribute end handle.

char_uuid

Characteristic UUID.

result

Points to the characteristic found in the service.

count

The number of specified attribute types found in the local GATTC cache.

  1. esp_ble_gattc_register_for_notify(): Register to receive notifications or indications of characteristics. Refer to GATT Client API.

Parameter Explanation

Input Parameters

Parameter Description

gattc_if

GATT client access interface.

server_bda

Target GATT server device address.

handle

Target GATT characteristic handle.

  1. esp_ble_gattc_get_descr_by_char_handle(): Used to get the descriptor of the specified characteristic handle in the local GATTC cache. Refer to GATT Client API.

Parameter explanation

Input parameters

Parameter description

gattc_if

GATT client access interface.

conn_id

Connection ID.

char_handle

Characteristic handle.

descr_uuid

Descriptor UUID.

result

Points to the characteristic found in the service.

count

The number of specified attribute types found in the local GATTC cache.

  1. esp_ble_gattc_write_char_descr(): Used to write the characteristic descriptor value of the specified descriptor handle. Refer to GATT Client API.

Parameter explanation

Input parameters

Parameter description

gattc_if

GATT client access interface.

conn_id

Connection ID.

handle

Descriptor handle to be written.

value_len

Byte length of the value to be written.

value

Value to be written.

write_type

Attribute write operation type.

auth_req

Authentication request type.

  1. esp_ble_gattc_write_char(): Used to write the characteristic value of the specified characteristic handle. Refer to GATT Client API.

Parameter Explanation

Input Parameter

Parameter Description

gattc_if

GATT client access interface.

conn_id

Connection ID.

handle

Descriptor handle to be written.

value_len

Byte length of the value to be written.

value

Value to be written.

write_type

Attribute write operation type.

auth_req

Authentication request type.

GAP Broadcast and Device Information

  1. esp_ble_gap_set_device_name(): Used to set the name of the local Bluetooth device. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

name

Device name.

  1. esp_ble_gap_config_adv_data_raw(): Used to set raw broadcast data. Refer to GAP API.

  2. esp_ble_gap_config_scan_rsp_data_raw(): Used to set raw scan response data. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

raw_data

Raw scan response data.

raw_data_len

Length of raw scan response data.

  1. esp_ble_gap_config_adv_data(): Used to override the default BTA broadcast parameters. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

adv_data

Pointer to the user-defined broadcast data structure.

  1. esp_ble_gap_register_callback(): Used to trigger GAP events, such as scan results. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

callback

Pointer to the application callback function.

  1. esp_ble_gap_update_conn_params: Used to update connection parameters, only available when the connection has been established. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

params

Connection update parameters.

  1. esp_ble_gap_start_advertising(): Used to start broadcasting. Refer to GAP API.

Parameter Explanation

Input Parameter

Parameter Description

adv_params

Pointer to the user-defined broadcast data structure.

  1. esp_ble_gap_start_scanning(): Continuously scan surrounding broadcast devices. Refer to GAP API.

Parameter Explanation

Input Parameters

Parameter Description

duration

The duration of the scan, in seconds.

  1. esp_ble_gap_stop_scanning(): Used to stop scanning. Refer to GAP API.

  1. esp_ble_resolve_adv_data_by_type(): Used to obtain broadcast data of a specified data type. Refer to GAP API.

Parameter Explanation

Input Parameters

Parameter Description

adv_data

Pointer to the broadcast data to be resolved.

adv_data_len

Length of the broadcast data.

type

The type of broadcast data to find.

length

Returns the length of the corresponding type of broadcast data (excluding the type field).

  1. esp_ble_gap_set_scan_params(): Used to set scan parameters. Refer to GAP API.

Parameter Explanation

Input Parameters

Parameter Description

scan_params

Pointer to the user-defined scan data structure.