Merge branch 'bugfix/fix_bluedroid_read_multi_v5.4' into 'release/v5.4'

fix(ble/bluedroid): fix GATT Read Multiple response handling (5.4)

See merge request espressif/esp-idf!50707
This commit is contained in:
Island
2026-07-15 15:38:55 +08:00
26 changed files with 174 additions and 145 deletions

View File

@@ -254,31 +254,6 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR
goto end;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) {
extend_adv_cb.inst[instance].connetable = true;
} else {
extend_adv_cb.inst[instance].connetable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE) {
extend_adv_cb.inst[instance].scannable = true;
} else {
extend_adv_cb.inst[instance].scannable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
extend_adv_cb.inst[instance].legacy_pdu = true;
} else {
extend_adv_cb.inst[instance].legacy_pdu = false;
}
if (params->type & (BTM_BLE_GAP_SET_EXT_ADV_PROP_DIRECTED |
BTM_BLE_GAP_SET_EXT_ADV_PROP_HD_DIRECTED)) {
extend_adv_cb.inst[instance].directed = true;
} else {
extend_adv_cb.inst[instance].directed = false;
}
#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
// if own_addr_type == BLE_ADDR_PUBLIC_ID or BLE_ADDR_RANDOM_ID,
if((params->own_addr_type == BLE_ADDR_PUBLIC_ID || params->own_addr_type == BLE_ADDR_RANDOM_ID) && BTM_GetLocalResolvablePrivateAddr(rand_addr)) {
@@ -315,6 +290,31 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR
}
#endif // (BT_BLE_FEAT_ADV_CODING_SELECTION == TRUE)
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) {
extend_adv_cb.inst[instance].connetable = true;
} else {
extend_adv_cb.inst[instance].connetable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE) {
extend_adv_cb.inst[instance].scannable = true;
} else {
extend_adv_cb.inst[instance].scannable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
extend_adv_cb.inst[instance].legacy_pdu = true;
} else {
extend_adv_cb.inst[instance].legacy_pdu = false;
}
if (params->type & (BTM_BLE_GAP_SET_EXT_ADV_PROP_DIRECTED |
BTM_BLE_GAP_SET_EXT_ADV_PROP_HD_DIRECTED)) {
extend_adv_cb.inst[instance].directed = true;
} else {
extend_adv_cb.inst[instance].directed = false;
}
extend_adv_cb.inst[instance].configured = true;
/* Record the post-fallback on-air address type for per-set conn_addr fixup. */
extend_adv_cb.inst[instance].own_addr_type = params->own_addr_type;

View File

@@ -612,6 +612,11 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(reason, p);
/* 0x00 is not a valid ATT error code; treat as unknown error. */
if (reason == GATT_SUCCESS) {
reason = GATT_UNKNOWN_ERROR;
}
if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
} else {
@@ -620,9 +625,6 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
(opcode == GATT_REQ_PREPARE_WRITE) &&
(p_attr) &&
(handle == p_attr->handle) ) {
if (reason == GATT_SUCCESS){
reason = GATT_ERROR;
}
p_clcb->status = reason;
gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
} else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&

View File

@@ -193,6 +193,66 @@ void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb)
memset( &p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD));
}
/*******************************************************************************
**
** Function gatt_find_multi_rsp_by_handle
**
** Description Find a read-multiple response entry by attribute handle.
** occurrence selects the Nth matching entry (for duplicate
** handles in the same request).
**
** Returns Pointer to response, or NULL if not found
**
*******************************************************************************/
static tGATTS_RSP *gatt_find_multi_rsp_by_handle(tGATT_SR_CMD *p_cmd, UINT16 handle,
UINT16 occurrence)
{
list_t *list;
const list_node_t *node;
UINT16 match_count = 0;
if (p_cmd->multi_rsp_q == NULL || fixed_queue_is_empty(p_cmd->multi_rsp_q)) {
return NULL;
}
list = fixed_queue_get_list(p_cmd->multi_rsp_q);
for (node = list_begin(list); node != list_end(list); node = list_next(node)) {
tGATTS_RSP *p_rsp = (tGATTS_RSP *)list_node(node);
if (p_rsp->attr_value.handle == handle) {
if (match_count == occurrence) {
return p_rsp;
}
match_count++;
}
}
return NULL;
}
/*******************************************************************************
**
** Function gatt_get_multi_handle_occurrence
**
** Description Return occurrence index of handle at multi_req index.
**
** Returns occurrence count
**
*******************************************************************************/
static UINT16 gatt_get_multi_handle_occurrence(tGATT_SR_CMD *p_cmd, UINT16 index)
{
UINT16 ii;
UINT16 occurrence = 0;
for (ii = 0; ii < index; ii++) {
if (p_cmd->multi_req.handles[ii] == p_cmd->multi_req.handles[index]) {
occurrence++;
}
}
return occurrence;
}
/*******************************************************************************
**
** Function process_read_multi_rsp
@@ -251,24 +311,12 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
*p++ = GATT_RSP_READ_MULTI;
p_buf->len = 1;
/* Now walk through the buffers putting the data into the response in order */
list_t *list = NULL;
const list_node_t *node = NULL;
if (! fixed_queue_is_empty(p_cmd->multi_rsp_q)) {
list = fixed_queue_get_list(p_cmd->multi_rsp_q);
}
/* Walk request handles in order; match responses by handle because
* stack (sync) and app (async) replies may arrive out of order. */
for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) {
tGATTS_RSP *p_rsp = NULL;
if (list != NULL) {
if (ii == 0) {
node = list_begin(list);
} else {
node = list_next(node);
}
if (node != list_end(list)) {
p_rsp = (tGATTS_RSP *)list_node(node);
}
}
tGATTS_RSP *p_rsp = gatt_find_multi_rsp_by_handle(
p_cmd, p_cmd->multi_req.handles[ii],
gatt_get_multi_handle_occurrence(p_cmd, ii));
if (p_rsp != NULL) {
@@ -283,16 +331,11 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
len = p_rsp->attr_value.len;
}
if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) {
memcpy (p, p_rsp->attr_value.value, len);
if (!is_overflow) {
p += len;
}
p_buf->len += len;
} else {
p_cmd->status = GATT_NOT_FOUND;
break;
memcpy (p, p_rsp->attr_value.value, len);
if (!is_overflow) {
p += len;
}
p_buf->len += len;
if (is_overflow) {
break;
@@ -307,7 +350,7 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
/* Sanity check on the buffer length */
if (p_buf->len == 0) {
if (p_buf->len <= 1) {
GATT_TRACE_ERROR("process_read_multi_rsp - nothing found!!");
p_cmd->status = GATT_NOT_FOUND;
osi_free (p_buf);
@@ -378,24 +421,11 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
*p++ = GATT_RSP_READ_MULTI_VAR;
p_buf->len = 1;
/* Now walk through the buffers putting the data into the response in order */
list_t *list = NULL;
const list_node_t *node = NULL;
if (! fixed_queue_is_empty(p_cmd->multi_rsp_q)) {
list = fixed_queue_get_list(p_cmd->multi_rsp_q);
}
/* Match responses by handle; replies may arrive out of order. */
for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) {
tGATTS_RSP *p_rsp = NULL;
if (list != NULL) {
if (ii == 0) {
node = list_begin(list);
} else {
node = list_next(node);
}
if (node != list_end(list)) {
p_rsp = (tGATTS_RSP *)list_node(node);
}
}
tGATTS_RSP *p_rsp = gatt_find_multi_rsp_by_handle(
p_cmd, p_cmd->multi_req.handles[ii],
gatt_get_multi_handle_occurrence(p_cmd, ii));
if (p_rsp != NULL) {
@@ -407,16 +437,11 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
}
len = MIN(p_rsp->attr_value.len, (mtu - total_len)); // attribute value length
if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) {
GATT_TRACE_DEBUG("%s handle %x len %u", __func__, p_rsp->attr_value.handle, p_rsp->attr_value.len);
UINT16_TO_STREAM(p, p_rsp->attr_value.len);
memcpy (p, p_rsp->attr_value.value, len);
p += len;
p_buf->len += (2+len);
} else {
p_cmd->status = GATT_NOT_FOUND;
break;
}
GATT_TRACE_DEBUG("%s handle %x len %u", __func__, p_rsp->attr_value.handle, p_rsp->attr_value.len);
UINT16_TO_STREAM(p, p_rsp->attr_value.len);
memcpy (p, p_rsp->attr_value.value, len);
p += len;
p_buf->len += (2+len);
} else {
p_cmd->status = GATT_NOT_FOUND;
break;
@@ -425,7 +450,7 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
} /* loop through all handles*/
/* Sanity check on the buffer length */
if (p_buf->len == 0) {
if (p_buf->len <= 1) {
GATT_TRACE_ERROR("%s - nothing found!!", __func__);
p_cmd->status = GATT_NOT_FOUND;
osi_free (p_buf);
@@ -561,10 +586,12 @@ tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if,
ret_code = attp_send_sr_msg (p_tcb, p_tcb->sr_cmd.p_rsp_msg);
p_tcb->sr_cmd.p_rsp_msg = NULL;
} else {
if (p_tcb->sr_cmd.status == GATT_SUCCESS){
status = GATT_UNKNOWN_ERROR;
tGATT_STATUS err_status = p_tcb->sr_cmd.status;
if (err_status == GATT_SUCCESS) {
err_status = GATT_UNKNOWN_ERROR;
}
ret_code = gatt_send_error_rsp (p_tcb, status, op_code, p_tcb->sr_cmd.handle, FALSE);
ret_code = gatt_send_error_rsp (p_tcb, err_status, op_code, p_tcb->sr_cmd.handle, FALSE);
}
#if (BLE_EATT_INCLUDED == TRUE)

View File

@@ -1793,7 +1793,7 @@ UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y)
smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32 mod 10**6", 4);
#endif
SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
SMP_TRACE_WARNING("Value for numeric comparison = %d", vres);
return vres;
}

View File

@@ -6,7 +6,7 @@ This document provides a test case for BLE smartphone compatibility and includes
### What You Need
* ESP device which needs to flash [this test program] (https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c)
* ESP device which needs to flash [this test program](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c)
* Smartphone with LightBlue® Explorer app
### Initialization
@@ -24,7 +24,7 @@ Prior to conducting tests, please initialize the smartphone and the ESP device a
* For tests marked with (*) further in the document, please bear in mind the following:
* Your phone performance may affect the results of these tests. If such a test fails, it does not mean the phone fails to meet the test requirements, but that you need to arrange targeted tests.
* Taking "Test for Connection Success Rate" as an example: if the test cannot be passed for 10 consecutive times, you need to record how many times the test was passed and then arrange targeted tests.
* For extended testing, please use the [examples] (https://github.com/espressif/esp-idf/tree/master/examples/bluetooth) provided by Espressif.
* For extended testing, please use the [examples](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth) provided by Espressif.
## Test for ADV Performance (*)

View File

@@ -76,7 +76,7 @@ To test this example, you first run the [gatt_server_demo](../gatt_server), whic
This example will enable gatt server's notification function once the connection is established and then the devices start exchanging data.
Please, check this [tutorial](tutorial/Gatt_Client_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Gatt_Client_Example_Walkthrough.md) for more information about this example.
### Hardware Required

View File

@@ -4,7 +4,7 @@
In this tutorial, the GATT client example code for the ESP32 is reviewed. The code implements a Bluetooth Low Energy (BLE) Generic Attribute (GATT) client, which scans for nearby peripheral servers and connects to a predefined service. The client then searches for available characteristics and subscribes to a known characteristic in order to receive notifications or indications. The example can register an Application Profile and initializes a sequence of events, which can be used to configure Generic Access Profile (GAP) parameters and to handle events such as scanning, connecting to peripherals and reading and writing characteristics.
# Includes
## Includes
This example is located in the examples folder of the ESP-IDF under the [bluetooth/bluedroid/ble/gatt_client/main](../main). The [gattc_demo.c](../main/gattc_demo.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [gattc_demo.c](../main/gattc_demo.c) are:
@@ -25,7 +25,7 @@ This example is located in the examples folder of the ESP-IDF under the [bluetoo
#include "esp_gatt_common_api.h"
```
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `bt.h`, `esp_bt_main.h`, `"esp_gap_ble_api.h"` and `esp_gattc_api.h`, which expose the BLE APIs required to implement this example.
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `"bt.h"`, `"esp_bt_main.h"`, `"esp_gap_ble_api.h"` and `"esp_gattc_api.h"`, which expose the BLE APIs required to implement this example.
* `bt.h`: configures the BT controller and VHCI from the host side.
* `esp_bt_main.h`: initializes and enables the Bluedroid stack.
@@ -34,7 +34,7 @@ These `includes` are required for the FreeRTOS and underlying system components
## Main Entry Point
The programs entry point is the app_main() function:
The program's entry point is the app_main() function:
```c
void app_main()
@@ -413,7 +413,7 @@ ESP_LOGI(GATTC_TAG, "searched Device Name Len %d", adv_name_len);
ESP_LOG_BUFFER_CHAR(GATTC_TAG, adv_name, adv_name_len);
```
Finally if the remote device name is the same as we have defined above, the local device stops scanning and tries to open a connection to the remote device using the `esp_ble_gattc_enh_open()` function. This function takes as parameters the Application Profile GATT interface, the remote server address and a boolean value. The boolean value is used to indicate if the connection is done directly or if its done in the background (auto-connection), at the moment this boolean value must be set to true in order to establish the connection. Notice that the client opens a virtual connection to the server. The virtual connection returns a connection ID. The virtual connection is the connection between the Application Profile and the remote server. Since many Application Profiles can run on one ESP32, there could be many virtual connection opened to the same remote server. There is also the physical connection which is the actual BLE link between the client and the server. Therefore, if the physical connection is disconnected with the `esp_ble_gap_disconnect()` function, all other virtual connections are closed as well. In this example, each Application Profile creates a virtual connection to the same server with the `esp_ble_gattc_enh_open()` function, so when the close function is called, only that connection from the Application Profile is closed, while if the gap disconnect function is called, both connections will be closed. In addition, connect events are propagated to all profiles because it relates to the physical connection, while open events are propagated only to the profile that creates the virtual connection.
Finally if the remote device name is the same as we have defined above, the local device stops scanning and tries to open a connection to the remote device using the `esp_ble_gattc_enh_open()` function. This function takes as parameters the Application Profile GATT interface, the remote server address and a boolean value. The boolean value is used to indicate if the connection is done directly or if it's done in the background (auto-connection), at the moment this boolean value must be set to true in order to establish the connection. Notice that the client opens a virtual connection to the server. The virtual connection returns a connection ID. The virtual connection is the connection between the Application Profile and the remote server. Since many Application Profiles can run on one ESP32, there could be many virtual connection opened to the same remote server. There is also the physical connection which is the actual BLE link between the client and the server. Therefore, if the physical connection is disconnected with the `esp_ble_gap_disconnect()` function, all other virtual connections are closed as well. In this example, each Application Profile creates a virtual connection to the same server with the `esp_ble_gattc_enh_open()` function, so when the close function is called, only that connection from the Application Profile is closed, while if the gap disconnect function is called, both connections will be closed. In addition, connect events are propagated to all profiles because it relates to the physical connection, while open events are propagated only to the profile that creates the virtual connection.
## Configuring the MTU Size
@@ -627,7 +627,7 @@ case ESP_GATTC_SEARCH_CMPL_EVT:
break;
```
`esp_ble_gattc_get_attr_count()` gets the attribute count with the given service or characteristic in the gattc cache. The parameters of `esp_ble_gattc_get_attr_count()` function are the GATT interface, the connection ID, the attribute type defined in `esp_gatt_db_attr_type_t`, the attribute start handle, the attribute end handle, the characteristic handle (this parameter is only valid when the type is set to `ESP_GATT_DB_DESCRIPTOR`.) and output the number of attribute has been found in the gattc cache with the given attribute type. Then we allocate a buffer to save the char information for `esp_ble_gattc_get_char_by_uuid()` function. The function finds the characteristic with the given characteristic UUID in the gattc cache. It just gets characteristic from local cache, instead of the remote devices. In a server, there might be more than one chars sharing the same UUID. However, in our gatt_server demo, every char has an unique UUID and thats why we only use the first char in `char_elem_result`, which is the pointer to the characteristic of the service. Count initially stores the number of the characteristics that the client wants to find, and will be updated with the number of the characteristics that have been actually found in the gattc cache with `esp_ble_gattc_get_char_by_uuid`.
`esp_ble_gattc_get_attr_count()` gets the attribute count with the given service or characteristic in the gattc cache. The parameters of `esp_ble_gattc_get_attr_count()` function are the GATT interface, the connection ID, the attribute type defined in `esp_gatt_db_attr_type_t`, the attribute start handle, the attribute end handle, the characteristic handle (this parameter is only valid when the type is set to `ESP_GATT_DB_DESCRIPTOR`.) and output the number of attribute has been found in the gattc cache with the given attribute type. Then we allocate a buffer to save the char information for `esp_ble_gattc_get_char_by_uuid()` function. The function finds the characteristic with the given characteristic UUID in the gattc cache. It just gets characteristic from local cache, instead of the remote devices. In a server, there might be more than one chars sharing the same UUID. However, in our gatt_server demo, every char has an unique UUID and that's why we only use the first char in `char_elem_result`, which is the pointer to the characteristic of the service. Count initially stores the number of the characteristics that the client wants to find, and will be updated with the number of the characteristics that have been actually found in the gattc cache with `esp_ble_gattc_get_char_by_uuid`.
## Registering for Notifications
@@ -723,7 +723,7 @@ Where `ESP_GATT_UUID_CHAR_CLIENT_CONFIG` is defined with the UUID to identify th
```c
#define ESP_GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
```
The value to write is “1” to enable notifications. We also pass `ESP_GATT_WRITE_TYPE_RSP` to request that the server responds to the request of enabling notifications and `ESP_GATT_AUTH_REQ_NONE` to indicate that the Write request does not need authorization.
The value to write is "1" to enable notifications. We also pass `ESP_GATT_WRITE_TYPE_RSP` to request that the server responds to the request of enabling notifications and `ESP_GATT_AUTH_REQ_NONE` to indicate that the Write request does not need authorization.

View File

@@ -73,7 +73,7 @@ There are some important points for this demo:
2. `esp_ble_set_encryption` should be used to start encryption with peer device. If the peer device initiates the encryption, `esp_ble_gap_security_rsp` should be used to send security response to the peer device when `ESP_GAP_BLE_SEC_REQ_EVT` is received.
3. The `gatt_security_client_demo` will receive a `ESP_GAP_BLE_AUTH_CMPL_EVT` once the encryption procedure has completed.
Please, check this [tutorial](tutorial/Gatt_Security_Client_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Gatt_Security_Client_Example_Walkthrough.md) for more information about this example.
### Hardware Required

View File

@@ -7,7 +7,7 @@ This example shows how to use the APIs to connect to and encrypt with peer devic
To test this example, you can run [gatt_security_client_demo](../gatt_security_client), which starts scanning, connects to and starts encryption with `gatt_security_server_demo` automatically.
Please, check this [tutorial](tutorial/Gatt_Security_Server_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Gatt_Security_Server_Example_Walkthrough.md) for more information about this example.
## Flow Diagram

View File

@@ -11,7 +11,7 @@ This demo creates GATT a service and then starts advertising, waiting to be conn
To test this demo, we can run the [gatt_client_demo](../gatt_client), which can scan for and connect to this demo automatically. They will start exchanging data once the GATT client has enabled the notification function of the GATT server.
Please, check this [tutorial](tutorial/Gatt_Server_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Gatt_Server_Example_Walkthrough.md) for more information about this example.
## Flow Diagram

View File

@@ -6,7 +6,7 @@ In this document, we review the GATT SERVER example code which implements a Blue
## Includes
First, lets take a look at the includes:
First, let's take a look at the includes:
```c
#include <stdio.h>
@@ -947,7 +947,7 @@ case ESP_GATTS_EXEC_WRITE_EVT:
example_exec_write_event_env(&a_prepare_write_env, param);
break;
```
Lets take a look at the Executive Write function:
Let's take a look at the Executive Write function:
```c
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){

View File

@@ -5,7 +5,7 @@
This example shows how to create a GATT service with an attribute table defined in one place. Provided API releases the user from adding attributes one by one as implemented in BLUEDROID. A demo of the other method to create the attribute table is presented in [gatt_server_demo](../gatt_server).
Please, check this [tutorial](tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md) for more information about this example.
## Flow Diagram

View File

@@ -2,7 +2,7 @@
## Introduction
This document presents a walkthrough of the GATT Server Service Table example code for the ESP32. This example implements a Bluetooth Low Energy (BLE) Generic Attribute (GATT) Server using a table-like data structure to define the server services and characteristics such as the one shown in the figure below Therefore, it demonstrates a practical way to define the server functionality in one place instead of adding services and characteristics one by one.
This document presents a walkthrough of the GATT Server Service Table example code for the ESP32. This example implements a Bluetooth Low Energy (BLE) Generic Attribute (GATT) Server using a table-like data structure to define the server services and characteristics such as the one shown in the figure below. Therefore, it demonstrates a practical way to define the server functionality in one place instead of adding services and characteristics one by one.
This example implements the *Heart Rate Profile* as defined by the [Traditional Profile Specifications](https://www.bluetooth.com/specifications/profiles-overview).
@@ -10,7 +10,7 @@ This example implements the *Heart Rate Profile* as defined by the [Traditional
## Includes
Lets start by taking a look at the included headers in the [gatts_table_creat_demo.c](../main/gatts_table_creat_demo.c) file:
Let's start by taking a look at the included headers in the [gatts_table_creat_demo.c](../main/gatts_table_creat_demo.c) file:
```c
#include "freertos/FreeRTOS.h"
@@ -26,7 +26,7 @@ Lets start by taking a look at the included headers in the [gatts_table_creat
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include gatts_table_creat_demo.h"
#include "gatts_table_creat_demo.h"
```
These includes are required for the *FreeRTOS* and underlying system components to run, including logging functionality and a library to store data in non-volatile flash memory. We are interested in ``bt.h``, ``esp_bt_main.h``, ``esp_gap_ble_api.h`` and ``esp_gatts_api.h`` which expose the BLE APIs required to implement this example.

View File

@@ -1,9 +1,9 @@
# GATT Client Multi-connection Example Walkthrough
## Introduction
This document presents a description of the multi-connection BLE GATT client example for the ESP32. In this implementation, a single ESP32 working as a GATT client connects to three different GATT servers at the same time. This set up illustrates the use case of an ESP32 device acting in a way so that it receives data from different BLE sensors. The unique combination of ESP32s BLE + Wi-Fi capabilities in addition to connection to multiple peripherals makes it a great candidate to serve as an IoT gateway.
This document presents a description of the multi-connection BLE GATT client example for the ESP32. In this implementation, a single ESP32 working as a GATT client connects to three different GATT servers at the same time. This set up illustrates the use case of an ESP32 device acting in a way so that it receives data from different BLE sensors. The unique combination of ESP32's BLE + Wi-Fi capabilities in addition to connection to multiple peripherals makes it a great candidate to serve as an IoT gateway.
This examples workflow is similar to the [GATT Client Example Walkthrough](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md) and is shown in the figure below. However, in the multi-connection implementation, a GATT client searches for three specific server names and once that it has found them it opens a connection to all three of them one after the other. In code, each connection is handled separately with one Application Profile.
This example's workflow is similar to the [GATT Client Example Walkthrough](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md) and is shown in the figure below. However, in the multi-connection implementation, a GATT client searches for three specific server names and once that it has found them it opens a connection to all three of them one after the other. In code, each connection is handled separately with one Application Profile.
Four ESP32 devices are needed in order to demonstrate this example, among which:
@@ -13,7 +13,7 @@ Four ESP32 devices are needed in order to demonstrate this example, among which:
<div align="center"><img src="image/Multi_Connection_GATT_Client_Flowchart.png" width = "800" alt="Multi-Connection GATT Client Flowchart" align=center/></div>
## Includes
The multi-connection examples main source file is [gattc_multi_connect.c](../main/gattc_multi_connect.c). For details, see Section [Includes](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md#includes) in [GATT Client Example Walkthrough](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md).
The multi-connection example's main source file is [gattc_multi_connect.c](../main/gattc_multi_connect.c). For details, see Section [Includes](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md#includes) in [GATT Client Example Walkthrough](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md).
## Main Entry Point
See Section [Main Entry Point](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md#main-entry-point) in [GATT Client Example Walkthrough](../../gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md).
@@ -69,7 +69,7 @@ See Section [Getting Scan Results](../../gatt_client/tutorial/Gatt_Client_Exampl
* Then, the device name found is compared to the server names that the client wants to connect to. The server names are defined in the ``remote_device_name`` array:
```c
static const char remote_device_name[3][20] = {"ESP_GATTS_DEMO_1", "ESP_GATTS_DEMO_2", ESP_GATTS_DEMO_3"};
static const char remote_device_name[3][20] = {"ESP_GATTS_DEMO_1", "ESP_GATTS_DEMO_2", "ESP_GATTS_DEMO_3"};
```
The name comparison takes places as follows:
@@ -334,7 +334,7 @@ At this point the client has acquired all characteristics from the remote device
```c
#define ESP_GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
```
The value to write is “1” to enable notifications. The parameter ``ESP_GATT_WRITE_TYPE_RSP`` is also passed to request that the server responds to the write request, as well as the ``ESP_GATT_AUTH_REQ_NONE`` parameter to indicate that the write request does not need authorization:
The value to write is "1" to enable notifications. The parameter ``ESP_GATT_WRITE_TYPE_RSP`` is also passed to request that the server responds to the write request, as well as the ``ESP_GATT_AUTH_REQ_NONE`` parameter to indicate that the write request does not need authorization:
```c
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {

View File

@@ -22,7 +22,7 @@ There are some important points for this demo:
`esp_ble_gap_security_rsp` should be used to send security response to the peer device when `ESP_GAP_BLE_SEC_REQ_EVT` is received.
3. The `gatt_security_client_demo` will receive a `ESP_GAP_BLE_AUTH_CMPL_EVT` once the encryption procedure has completed.
Please, check this [tutorial](tutorial/ble50_security_client_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/ble50_security_client_Example_Walkthrough.md) for more information about this example.
### Hardware Required

View File

@@ -7,9 +7,9 @@
* The peripheral device is normally a GATT Server that exposes Services and Characteristics. The peripheral replies with a *Aux Connect Pairing Response* followed by authentication and exchange of keys. If the bonding process is also executed, the Long Term Keys are stored for subsequent connections. Finally an encrypted channel is established which can support protection against Man-In-The-Middle (MITM) attacks depending on the security configuration.
* The code is implemented using an Application Profile that upon registration, allows to set the local privacy configuration as events are triggered during the life time of the program.
This document only includes a description of the security aspects of the BLE5.0 Security GATT Client implementation, for the more info about extended scan , periodic scan please refer to [Periodic_Sync_Example Walkthrough] (../../periodic_sync/tutorial/Periodic_Sync_Example_Walkthrough.md).
This document only includes a description of the security aspects of the BLE5.0 Security GATT Client implementation. For more information about extended scan and periodic scan, please refer to [Periodic Sync Example Walkthrough](../../periodic_sync/tutorial/Periodic_Sync_Example_Walkthrough.md).
##include
## Includes
```c
#include <stdint.h>
@@ -27,7 +27,7 @@ This document only includes a description of the security aspects of the BLE5.0
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
```
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `bt.h`, `esp_bt_main.h`, `"esp_gap_ble_api.h"` and `esp_gattc_api.h`, which expose the BLE APIs required to implement this example.
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `"bt.h"`, `"esp_bt_main.h"`, `"esp_gap_ble_api.h"` and `"esp_gattc_api.h"`, which expose the BLE APIs required to implement this example.
* `bt.h`: configures the BT controller and VHCI from the host side.
* `esp_bt_main.h`: initializes and enables the Bluedroid stack.

View File

@@ -7,7 +7,7 @@ This example shows how to use the APIs to connect in secure manner with peer dev
To test this example, you can run [ble50_security_client_demo](../ble50_security_client), which starts scanning, connects to and starts encryption with `ble50_sec_gattc_demo` automatically.
Please, check this [tutorial](tutorial/ble50_security_server_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/ble50_security_server_Example_Walkthrough.md) for more information about this example.
## How to Use Example

View File

@@ -1,11 +1,11 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- |
#ESP-IDF Multi Adv Example
# ESP-IDF Multi Adv Example
This example support legacy as well as extended advertisement for all phy.
This example supports legacy as well as extended advertisement for all phy.
Please, check this [tutorial](tutorial/Mulit_Adv_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Mulit_Adv_Example_Walkthrough.md) for more information about this example.
## How to Use Example

View File

@@ -1,12 +1,12 @@
# Multi Adv Example Walkthrough
## introduction
## Introduction
In this document, we review the Multi Adv example code which implements a Bluetooth Low Energy (BLE5.0) Multi adv profile on the ESP32C3. This example is designed around two Application Profiles and a series of events that are handled in order to execute a sequence of configuration steps, such as defining extended advertising parameters with all phy 1M,2M and coded and Ext adv data.
## Includes
First, lets take a look at the include
First, let's take a look at the include
```c
#include <stdio.h>
@@ -162,7 +162,7 @@ shed to the application from the BLE stack.
The register application event is the first one that is triggered during the lifetime of the program, this example uses the Profile A GATT event handle to configure the advertising parameters upon registration. This example has the option to use both standard Bluetooth Core Specification advertising parameters or a customized raw buffer. The option can be selected with the `CONFIG_SET_RAW_ADV_DATA` define. The raw advertising data can be used to implement iBeacons, Eddystone or other proprietary, and custom frame types such as the ones used for Indoor Location Services that are different from the standard specifications.
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy in esp_ble_gap_ext_adv_set_params , esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy in esp_ble_gap_ext_adv_set_params, esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
```c
/**
@@ -268,7 +268,7 @@ rt.status);
}
```
## Default config
## Default Config
This example by default configured with
1M phy extend adv, Connectable advertising

View File

@@ -1,15 +1,15 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- |
# ESP_IDF Periodic Adv Example
# ESP-IDF Periodic Adv Example
This example support for the periodic advertisement which allow the scanner to sync with the advertiser so that scanner and advertiser wake up same time. It support extended adv with 2M phy in connectable mode.
This example supports the periodic advertisement which allow the scanner to sync with the advertiser so that scanner and advertiser wake up same time. It support extended adv with 2M phy in connectable mode.
To test this demo, we can run the [periodic_sync_demo](../periodic_sync), which can do periodic scan and try to sync with periodic adv.
Please, check this [tutorial](tutorial/Periodic_adv_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Periodic_adv_Example_Walkthrough.md) for more information about this example.
## How to Use Example

View File

@@ -1,11 +1,11 @@
# Periodic Adv Example Walkthrough
## introduction
## Introduction
In this document, We review the Periodic Adv example code which implements a Bluetooth Low Energy (BLE5.0) Multi adv profile on the ESP32C3. This example is designed the periodic advertisement which allow the scanner to sync with the advertiser so that scanner and advertiser wake up same time.
##include
First, lets take a look at the include
## Includes
First, let's take a look at the include
```c
#include <stdio.h>
@@ -166,7 +166,7 @@ The functions `gap_event_handler()` handle all the events that are pushed to th
The register application event is the first one that is triggered during the lifetime of the program, this example uses the Profile A GATT event handle to configure the advertising parameters upon registration. This example has the option to use both standard Bluetooth Core Specification advertising parameters or a customized raw buffer. The option can be selected with the `CONFIG_SET_RAW_ADV_DATA` define. The raw advertising data can be used to implement iBeacons, Eddystone or other proprietaries, and custom frame types such as the ones used for Indoor Location Services that are different from the standard specifications.
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy is esp_ble_gap_ext_adv_set_params , esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy is esp_ble_gap_ext_adv_set_params, esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
```c
/**
@@ -299,7 +299,7 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
}
}
```
## Default config
## Default Config
2M phy with connectable mode of periodic adv.

View File

@@ -7,7 +7,7 @@ This example supports the periodic extended scan to scan the extended advertisem
To test this demo, we can run the [periodic_adv_demo](../periodic_adv), which can start extended advertisement with supported param.
Please, check this [tutorial](tutorial/Periodic_Sync_Example_Walkthrough.md) for more information about this example.
Please check this [tutorial](tutorial/Periodic_Sync_Example_Walkthrough.md) for more information about this example.
## How to Use Example

View File

@@ -1,12 +1,12 @@
#Periodic Sync Example Walkthrough
# Periodic Sync Example Walkthrough
## Introduction
In this tutorial, the Periodic sync example code for the ESP32C3 is reviewed. The code implement Bluetooth Low Energy (BLE5.0) periodic sync , which scans for nearby peripheral which can support legacy, extended and periodic advertisement. Periodic Sync allow the advertiser to sync with scanner so that scanner and advertiser wake up at same time.
In this tutorial, the Periodic sync example code for the ESP32C3 is reviewed. The code implement Bluetooth Low Energy (BLE5.0) periodic sync, which scans for nearby peripheral which can support legacy, extended and periodic advertisement. Periodic Sync allow the advertiser to sync with scanner so that scanner and advertiser wake up at same time.
* ADV_EXT_IND is over primary advertising channels
* AUX_ADV_IND and AUX_SYNC_IND are over secondary advertising channels
Little info about the EXT_ADV_IND , AUX_ADV_IND and AUX_SYNC_IND with scanner support of periodic sync.
Little info about the EXT_ADV_IND, AUX_ADV_IND and AUX_SYNC_IND with scanner support of periodic sync.
ADV_EXT_IND is over primary advertising channels and is used to indicate that an advertisement will be sent on a secondary advertisement channel. The information in ADV_EXT_IND will inform the scanner:
@@ -35,7 +35,7 @@ With this information, the scanner can synchronize with the advertiser and they
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
@@ -49,7 +49,7 @@ With this information, the scanner can synchronize with the advertiser and they
#include "freertos/semphr.h"
```
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `bt.h`, `esp_bt_main.h`, `"esp_gap_ble_api.h"` and `esp_gattc_api.h`, which expose the BLE APIs required to implement this example.
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `"bt.h"`, `"esp_bt_main.h"`, `"esp_gap_ble_api.h"` and `"esp_gattc_api.h"`, which expose the BLE APIs required to implement this example.
* `esp_bt.h`: configures the BT controller and VHCI from the host side.
* `esp_bt_main.h`: initializes and enables the Bluedroid stack.

View File

@@ -31,7 +31,7 @@ To exit the serial monitor, type `Ctrl-]`.
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
# TUTORIAL
## Tutorial
## Includes
@@ -59,7 +59,7 @@ These `includes` are required for the FreeRTOS and underlying system components
## Main Entry Point
The programs entry point is the `app_main()` function.
The program's entry point is the `app_main()` function.
### Non-volatile Storage Library Initialization

View File

@@ -1,7 +1,7 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# ESP-IDF BT-SPP-INITATOR demo
# ESP-IDF BT-SPP-INITIATOR demo
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP initiator which performs as a client. we aggregate **Secure Simple Pair** (**SSP**) into this demo to show how to use SPP when creating your own APPs. We also provide the demo `bt_spp_acceptor` or the demo `bt_spp_vfs_acceptor` to create an SPP acceptor which performs as a server. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.
@@ -45,17 +45,17 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
After the program starts, the example will initiate a Bluetooth discovery procedure and filter out the peer device by the name in the EIR(Extended Inquiry Response). After discovering the SPP service, it will connect to the SPP acceptor and send data. The example will calculate the data rate or print the sent data after the SPP connection is established.
### Example Output
When you run this example and the IO capability is `ESP_IO_CAP_IO` or `ESP_IO_CAP_IN` , the commands help table prints the following at the very beginning:
When you run this example and the IO capability is `ESP_IO_CAP_IO` or `ESP_IO_CAP_IN`, the commands help table prints the following at the very beginning:
```
########################################################################
Supported commands are as follows, arguments are embraced with < and >
spp h; -- show command manual
Use this cmmand table if the IO Capability of local device set as IO_CAP_IO.
Use this command table if the IO Capability of local device set as IO_CAP_IO.
spp ok; -- manual Numeric Confirmation.
Use this cmmand table if the IO Capability of local device set as IO_CAP_IN.
Use this command table if the IO Capability of local device set as IO_CAP_IN.
spp key <auth key>; -- manual Passkey. (e.g. spp key 136245;)
########################################################################
@@ -114,7 +114,7 @@ Whether you should passkey or confirm the number also depends on the IO capabili
## Example Breakdown
To clearly show how the SSP aggregate with the SPP , we use the Commands and Effects scheme to illustrate the process of secure paring and connection establishment.
To clearly show how the SSP aggregate with the SPP, we use the Commands and Effects scheme to illustrate the process of secure paring and connection establishment.
- The example will respond to user command through UART console. Please go to `console_uart.c` for the configuration details.
@@ -127,7 +127,7 @@ Q: How to change the process of SSP?
A: Users can set the IO Capability and Security Mask for their device (fixed Security Mode, Security Mode 4). In short, the Security Mask sets the security level for authentication stage and the IO Capability determines the way of user interaction during pairing. The default Security Mask of this demo is `ESP_SPP_SEC_AUTHENTICATE` which support MITM (Man In The Middle) protection. For more information about Security Simple Pair on ESP32, please refer to [ESP32_SSP](../bt_spp_acceptor/ESP32_SSP.md).
Q: How can we reach the maximum throughput when using SPP?
A: The default MTU size of classic Bluetooth SPP on ESP32 is 990 bytes, and higher throughput can be achieved in the case that data chunck size is close to the MTU size or multiple of MTU size. For example, sending 100 bytes data per second is much better than sending 10 bytes every 100 milliseconds.
A: The default MTU size of classic Bluetooth SPP on ESP32 is 990 bytes, and higher throughput can be achieved in the case that data chunk size is close to the MTU size or multiple of MTU size. For example, sending 100 bytes data per second is much better than sending 10 bytes every 100 milliseconds.
Q: What is the difference between the event `ESP_SPP_CONG_EVT` and the parameter `cong` of the event `ESP_SPP_WRITE_EVT`?
A: The event `ESP_SPP_CONG_EVT` shows the changing status from `congest` to `uncongest`, or form `uncongest` to `congest`. Congestion can have many causes, such as using out of the credit which is sent by peer, reaching the high watermark of the Tx buffer, the congestion at Bluetooth L2CAP layer and so on. The parameter `cong` of the event `ESP_SPP_WRITE_EVT` shows a snapshot of the state of the flow control manager after the write operation is completed. The user needs to carefully consider retransmitting or continuing to write according to these two events. The ESP32 offers an VFS mode of SPP which hides the details of retransmitting, but it will block the caller and is not more efficient than the callback mode.

View File

@@ -1,7 +1,7 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# ESP-IDF BT-SPP-INITATOR demo
# ESP-IDF BT-SPP-INITIATOR demo
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP initiator which performs as a client, and it will register into the VFS. we aggregate **Secure Simple Pair** (**SSP**) into this demo to show how to use SPP when creating your own APPs. We also provide the demo `bt_spp_acceptor` or the demo `bt_spp_vfs_acceptor` to create an SPP acceptor which performs as a server. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.