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.
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 isuint16_t
.
adv_int_max
: Maximum broadcast interval. The data type isuint16_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 isesp_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 isesp_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 isesp_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 isesp_ble_addr_type_t
. But it only supports public addresses and random addresses.
channel_map
: Broadcast channel. The data type isesp_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 isesp_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
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 isesp_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 isesp_ble_addr_type_t
.
scan_filter_policy
: Scan filter policy. The data type isesp_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 isuint16_t
.
scan_window
: Scan window, i.e., the actual scan duration within each scan cycle. The data type isuint16_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 isesp_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
.
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.
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, andp_manufacturer_data
should be set toNULL
.
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 setmanufacturer_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, andp_service_data
should be set toNULL
.
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:
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).
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:
Cache the received fragments into a temporary buffer and return a Prepare Write Response to confirm that the fragment has been received.
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.
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:
GATT Level |
Structure Member |
Description |
---|---|---|
Profile |
|
GATT Server callback function, used to bind the Profile with event handling logic, facilitating the handling of all client request events under this Profile. |
|
GATT interface ID, used to identify this Profile, distinguishing different Profiles or GATT interfaces. |
|
|
Application ID, used to identify the application to which this Profile belongs, distinguishing different instances when registering multiple Profiles. |
|
|
Connection ID, used to distinguish different client connections. |
|
Service |
|
Service handle, used for subsequent operations to access this service. |
|
Service identifier, including service UUID and primary/secondary service information. |
|
Characteristic |
|
Characteristic handle, used for subsequent operations to access this characteristic value. |
|
Characteristic UUID, convenient for clients to identify characteristics. |
|
|
Characteristic permissions, such as readable, writable, etc., determining the client’s access mode to the characteristic. |
|
|
Characteristic properties, specified by the program to support operations such as read, write, notify, indicate. |
|
Descriptor |
|
Descriptor handle, used for subsequent operations to access this descriptor. |
|
Descriptor UUID, commonly used to identify descriptors such as CCCD. |
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:
GATT Level |
Structure Member |
Description |
---|---|---|
Profile |
|
GATT Server callback function, binding Profile with event handling logic, used to handle all client request events under this Profile. |
|
GATT interface ID, identifying this Profile, used to distinguish different Profiles or GATT interfaces. |
|
|
Application ID, used to identify the application to which this Profile belongs, distinguishing different instances when registering multiple Profiles. |
|
|
Connection ID, used to distinguish different client connections. |
|
|
Remote device Bluetooth address, used to identify the connection target. |
|
Service |
|
Remote service start handle, used to identify the start position of the service in subsequent operations. |
|
Remote service end handle, used to identify the end position of the service in subsequent operations. |
|
Characteristic |
|
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:
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.
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.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.
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:
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Event type. |
Different processing can be performed in the callback based on the event type. |
|
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. |
|
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:
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.
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
andevent
, 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)
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.
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 useBT_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
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.
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.
esp_bluedroid_init()
: Used to initialize and allocate resources required by Bluetooth. Refer to Bluetooth API.
esp_bluedroid_enable()
: Used to enable Bluetooth. Refer to Bluetooth API.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
esp_ble_gap_config_adv_data_raw()
: Used to set raw broadcast data. Refer to GAP API.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.
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.
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.
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.
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.
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.
esp_ble_gap_stop_scanning()
: Used to stop scanning. Refer to GAP API.
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).
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.