Merge branch 'bugfix/fix_ble_security_issue_2025_v3_v5.5' into 'release/v5.5'
fix(ble/bluedroid): Fix type mismatch and length validation in HCI packet parser (v5.5) See merge request espressif/esp-idf!44667
This commit is contained in:
@@ -27,6 +27,24 @@ examples/bluetooth/bluedroid/ble:
|
||||
depends_filepatterns:
|
||||
- examples/bluetooth/bluedroid/ble/pytest_ble_test.py
|
||||
|
||||
examples/bluetooth/bluedroid/ble/ble_acl_latency/cent:
|
||||
<<: *bt_default_depends
|
||||
disable:
|
||||
- if: SOC_BLE_SUPPORTED != 1
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s3"]
|
||||
temporary: true
|
||||
reason: only enable build jobs for tested targets
|
||||
|
||||
examples/bluetooth/bluedroid/ble/ble_acl_latency/periph:
|
||||
<<: *bt_default_depends
|
||||
disable:
|
||||
- if: SOC_BLE_SUPPORTED != 1
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s3"]
|
||||
temporary: true
|
||||
reason: only enable build jobs for tested targets
|
||||
|
||||
examples/bluetooth/bluedroid/ble/ble_hid_device_demo:
|
||||
<<: *bt_default_depends
|
||||
disable:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -362,12 +362,16 @@ static void auto_io_gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_
|
||||
case ESP_GATTS_WRITE_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "Characteristic write, value len %u, value ", param->write.len);
|
||||
ESP_LOG_BUFFER_HEX(GATTS_TAG, param->write.value, param->write.len);
|
||||
if (param->write.value[0]) {
|
||||
ESP_LOGI(GATTS_TAG, "LED ON!");
|
||||
led_on();
|
||||
if (param->write.len > 0) {
|
||||
if (param->write.value[0]) {
|
||||
ESP_LOGI(GATTS_TAG, "LED ON!");
|
||||
led_on();
|
||||
} else {
|
||||
ESP_LOGI(GATTS_TAG, "LED OFF!");
|
||||
led_off();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(GATTS_TAG, "LED OFF!");
|
||||
led_off();
|
||||
ESP_LOGW(GATTS_TAG, "Empty write data received");
|
||||
}
|
||||
example_write_event_env(gatts_if, param);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_acl_latency_cent)
|
||||
@@ -0,0 +1,190 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-IDF BLE ACL Latency Test - Central
|
||||
|
||||
This example demonstrates how to measure BLE ACL (Asynchronous Connection-Less) link latency. The central device scans for the peripheral, connects to it, and then performs a latency test by sending packets and measuring the round-trip time (RTT).
|
||||
|
||||
This demo should be used together with the `periph` (peripheral) example.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. The central scans for a device named `ESP_ACL_LATENCY`
|
||||
2. Upon finding the peripheral, it connects and performs MTU exchange
|
||||
3. After enabling notifications, the central sends 100 test packets (242 bytes each)
|
||||
4. For each packet, the central records the send time
|
||||
5. When the echoed packet is received via notification, it calculates RTT
|
||||
6. Finally, statistics (average, min, max latency, packet loss) are printed
|
||||
|
||||
## Test Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Central │ │ Peripheral │
|
||||
│ (GATT Client)│ │ (GATT Server)│
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ──────────── Connection Setup ─────────── │
|
||||
│ │
|
||||
│ 1. Scan for "ESP_ACL_LATENCY" │
|
||||
│ ─────────────────────────────────────────> │ Advertising
|
||||
│ │
|
||||
│ 2. Connect Request │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 3. Connection Established │
|
||||
│ <─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 4. MTU Exchange (517 bytes) │
|
||||
│ <─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 5. Connection Parameter Update (7.5ms) │
|
||||
│ <─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 6. Service Discovery │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 7. Enable Notification (CCCD) │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ──────────── Latency Test ───────────── │
|
||||
│ │
|
||||
│ 8. Write Test Packet [SEQ=0] ──┐ │
|
||||
│ Record send_time t1│ │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ │ │ Echo back
|
||||
│ 9. Notification [SEQ=0] │ │ via Notify
|
||||
│ Record recv_time t2│ │
|
||||
│ <───────────────────────────────────────── │
|
||||
│ │ │
|
||||
│ RTT = t2 - t1 ──┘ │
|
||||
│ Latency = RTT / 2 │
|
||||
│ │
|
||||
│ ... Repeat for SEQ 1-99 ... │
|
||||
│ │
|
||||
│ 10. Print Statistics │
|
||||
│ - Average/Min/Max Latency │
|
||||
│ - Packet Loss Rate │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ Central │ │ Peripheral │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## Test Configuration
|
||||
|
||||
The following parameters can be modified in `gattc_latency.h`:
|
||||
|
||||
| Parameter | Default Value | Description |
|
||||
|------------------------|---------------|------------------------------------|
|
||||
| TEST_PACKET_COUNT | 100 | Number of test packets to send |
|
||||
| TEST_PACKET_INTERVAL_MS| 20 | Interval between packets (ms) |
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* Two development boards with supported SoC (e.g., ESP32-C3-DevKitC, ESP32-DevKitC, etc.)
|
||||
* Two USB cables for power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information.
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
1. First, flash the `periph` example to one board:
|
||||
|
||||
```bash
|
||||
cd ../periph
|
||||
idf.py -p PORT1 flash
|
||||
```
|
||||
|
||||
2. Then, flash this `cent` example to another board:
|
||||
|
||||
```bash
|
||||
cd ../cent
|
||||
idf.py -p PORT2 flash
|
||||
```
|
||||
|
||||
### Monitor
|
||||
|
||||
Run `idf.py -p PORT monitor` to view the serial output of the central device.
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (362) BLE_ACL_LATENCY_CENT: BLE ACL Latency Test - Central
|
||||
I (372) phy_init: phy_version 310,dde1ba9,Jun 4 2024,16:38:11
|
||||
I (432) BLE_ACL_LATENCY_CENT: REG_EVT
|
||||
I (442) BLE_ACL_LATENCY_CENT: scan start success
|
||||
I (442) BLE_ACL_LATENCY_CENT: Central initialized, scanning for peripheral...
|
||||
I (622) BLE_ACL_LATENCY_CENT: searched device ESP_ACL_LATENCY
|
||||
I (622) BLE_ACL_LATENCY_CENT: connect to the remote device.
|
||||
I (622) BLE_ACL_LATENCY_CENT: stop scan successfully
|
||||
I (892) BLE_ACL_LATENCY_CENT: ESP_GATTC_CONNECT_EVT conn_id 0, if 4
|
||||
I (892) BLE_ACL_LATENCY_CENT: REMOTE BDA: 58:cf:79:ea:77:30
|
||||
I (892) BLE_ACL_LATENCY_CENT: open success
|
||||
I (1042) BLE_ACL_LATENCY_CENT: update connection params status = 0, min_int = 6, max_int = 6,conn_int = 6,latency = 0, timeout = 500
|
||||
I (1112) BLE_ACL_LATENCY_CENT: discover service complete conn_id 0
|
||||
I (1112) BLE_ACL_LATENCY_CENT: service found
|
||||
I (1122) BLE_ACL_LATENCY_CENT: ESP_GATTC_CFG_MTU_EVT, Status 0, MTU 517, conn_id 0
|
||||
I (1132) BLE_ACL_LATENCY_CENT: ESP_GATTC_REG_FOR_NOTIFY_EVT
|
||||
I (1172) BLE_ACL_LATENCY_CENT: write descr success
|
||||
I (1172) BLE_ACL_LATENCY_CENT: Initializing latency test...
|
||||
I (1172) LATENCY_TEST: Latency test initialized, conn_id=0, handle=42
|
||||
I (2182) BLE_ACL_LATENCY_CENT: Starting latency test...
|
||||
I (2182) LATENCY_TEST: ====================================
|
||||
I (2182) LATENCY_TEST: Starting latency test...
|
||||
I (2182) LATENCY_TEST: Packets: 100, Interval: 20 ms
|
||||
I (2182) LATENCY_TEST: ====================================
|
||||
SEQ= 0, RTT= 20040 us, Latency= 10020 us (10.02 ms)
|
||||
SEQ= 1, RTT= 18341 us, Latency= 9170 us (9.17 ms)
|
||||
SEQ= 2, RTT= 13339 us, Latency= 6669 us (6.67 ms)
|
||||
...
|
||||
SEQ= 99, RTT= 15835 us, Latency= 7917 us (7.92 ms)
|
||||
I (4192) LATENCY_TEST: All packets sent, waiting for responses...
|
||||
I (6192) LATENCY_TEST:
|
||||
I (6192) LATENCY_TEST: ========================================
|
||||
I (6192) LATENCY_TEST: Test Results Summary
|
||||
I (6192) LATENCY_TEST: ========================================
|
||||
I (6192) LATENCY_TEST: Total packets: 100
|
||||
I (6202) LATENCY_TEST: Received: 100
|
||||
I (6202) LATENCY_TEST: Lost: 0 (0.0%)
|
||||
I (6202) LATENCY_TEST: ----------------------------------------
|
||||
I (6212) LATENCY_TEST: Average latency: 7929 us (7.93 ms)
|
||||
I (6222) LATENCY_TEST: Min latency: 6667 us (6.67 ms)
|
||||
I (6222) LATENCY_TEST: Max latency: 10020 us (10.02 ms)
|
||||
I (6232) LATENCY_TEST: ========================================
|
||||
```
|
||||
|
||||
## Connection Parameters
|
||||
|
||||
The example uses optimized connection parameters for low latency:
|
||||
|
||||
| Parameter | Value | Description |
|
||||
|---------------------|----------|--------------------------------|
|
||||
| Connection Interval | 7.5 ms | Minimum allowed by BLE spec |
|
||||
| Slave Latency | 0 | No skipped connection events |
|
||||
| Supervision Timeout | 4000 ms | Connection timeout |
|
||||
| MTU | 517 | Maximum ATT MTU |
|
||||
|
||||
## Understanding the Results
|
||||
|
||||
- **RTT (Round-Trip Time)**: Time from sending a packet until receiving the echo
|
||||
- **Latency**: Estimated one-way delay (RTT / 2)
|
||||
- **Expected Results**: With 7.5ms connection interval, typical latency is 6-10ms
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "gattc_latency_demo.c" "latency_test.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#ifndef H_GATTC_LATENCY_
|
||||
#define H_GATTC_LATENCY_
|
||||
|
||||
#include "esp_gattc_api.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Service and Characteristic UUIDs - must match peripheral */
|
||||
#define REMOTE_SERVICE_UUID 0x1234
|
||||
#define REMOTE_CHAR_UUID 0x5678
|
||||
|
||||
/* Profile ID */
|
||||
#define PROFILE_APP_ID 0
|
||||
#define INVALID_HANDLE 0
|
||||
|
||||
/* Remote device name */
|
||||
#define REMOTE_DEVICE_NAME "ESP_ACL_LATENCY"
|
||||
|
||||
/* Test configuration */
|
||||
#define TEST_PACKET_COUNT 100
|
||||
#define TEST_PACKET_INTERVAL_MS 20
|
||||
|
||||
/* Test packet structure */
|
||||
typedef struct {
|
||||
uint16_t seq_num;
|
||||
uint8_t payload[240];
|
||||
} __attribute__((packed)) test_packet_t;
|
||||
|
||||
/* Latency record */
|
||||
typedef struct {
|
||||
uint16_t seq;
|
||||
int64_t send_time_us;
|
||||
int64_t recv_time_us;
|
||||
bool received;
|
||||
} latency_record_t;
|
||||
|
||||
/* Latency test functions */
|
||||
void latency_test_init(uint16_t conn_id, uint16_t char_handle);
|
||||
void latency_test_start(void);
|
||||
void latency_test_handle_notify(uint8_t *data, uint16_t len);
|
||||
void latency_test_print_results(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_GATTC_LATENCY_ */
|
||||
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gattc_api.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "gattc_latency.h"
|
||||
|
||||
#define GATTC_TAG "BLE_ACL_LATENCY_CENT"
|
||||
|
||||
#define PROFILE_NUM 1
|
||||
#define PROFILE_APP_ID 0
|
||||
|
||||
static bool connect = false;
|
||||
static bool get_server = false;
|
||||
static esp_gattc_char_elem_t *char_elem_result = NULL;
|
||||
static esp_gattc_descr_elem_t *descr_elem_result = NULL;
|
||||
|
||||
/* Declare static functions */
|
||||
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
|
||||
static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
|
||||
|
||||
/* Extern function */
|
||||
extern void latency_test_set_gattc_if(esp_gatt_if_t gattc_if);
|
||||
|
||||
static esp_bt_uuid_t remote_filter_service_uuid = {
|
||||
.len = ESP_UUID_LEN_16,
|
||||
.uuid = {.uuid16 = REMOTE_SERVICE_UUID,},
|
||||
};
|
||||
|
||||
static esp_bt_uuid_t remote_filter_char_uuid = {
|
||||
.len = ESP_UUID_LEN_16,
|
||||
.uuid = {.uuid16 = REMOTE_CHAR_UUID,},
|
||||
};
|
||||
|
||||
static esp_bt_uuid_t notify_descr_uuid = {
|
||||
.len = ESP_UUID_LEN_16,
|
||||
.uuid = {.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG,},
|
||||
};
|
||||
|
||||
static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50), // 50ms
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30), // 30ms
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
struct gattc_profile_inst {
|
||||
esp_gattc_cb_t gattc_cb;
|
||||
uint16_t gattc_if;
|
||||
uint16_t app_id;
|
||||
uint16_t conn_id;
|
||||
uint16_t service_start_handle;
|
||||
uint16_t service_end_handle;
|
||||
uint16_t char_handle;
|
||||
esp_bd_addr_t remote_bda;
|
||||
};
|
||||
|
||||
static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
|
||||
[PROFILE_APP_ID] = {
|
||||
.gattc_cb = gattc_profile_event_handler,
|
||||
.gattc_if = ESP_GATT_IF_NONE,
|
||||
},
|
||||
};
|
||||
|
||||
static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
|
||||
{
|
||||
esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param;
|
||||
|
||||
switch (event) {
|
||||
case ESP_GATTC_REG_EVT:
|
||||
ESP_LOGI(GATTC_TAG, "REG_EVT");
|
||||
gl_profile_tab[PROFILE_APP_ID].gattc_if = gattc_if;
|
||||
esp_err_t scan_ret = esp_ble_gap_set_scan_params(&ble_scan_params);
|
||||
if (scan_ret){
|
||||
ESP_LOGE(GATTC_TAG, "set scan params error, error code = %x", scan_ret);
|
||||
}
|
||||
break;
|
||||
case ESP_GATTC_CONNECT_EVT:{
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT conn_id %d, if %d", p_data->connect.conn_id, gattc_if);
|
||||
gl_profile_tab[PROFILE_APP_ID].conn_id = p_data->connect.conn_id;
|
||||
memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
|
||||
ESP_LOGI(GATTC_TAG, "REMOTE BDA: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
p_data->connect.remote_bda[0], p_data->connect.remote_bda[1],
|
||||
p_data->connect.remote_bda[2], p_data->connect.remote_bda[3],
|
||||
p_data->connect.remote_bda[4], p_data->connect.remote_bda[5]);
|
||||
|
||||
/* Update connection parameters to minimum interval (7.5ms) for lower latency */
|
||||
esp_ble_conn_update_params_t conn_params = {0};
|
||||
memcpy(conn_params.bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
|
||||
conn_params.min_int = ESP_BLE_GAP_CONN_ITVL_MS(7.5); // 7.5ms - minimum allowed
|
||||
conn_params.max_int = ESP_BLE_GAP_CONN_ITVL_MS(7.5); // 7.5ms - minimum allowed
|
||||
conn_params.latency = 0;
|
||||
conn_params.timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(4000); // 4s
|
||||
esp_ble_gap_update_conn_params(&conn_params);
|
||||
|
||||
esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, p_data->connect.conn_id);
|
||||
if (mtu_ret){
|
||||
ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_OPEN_EVT:
|
||||
if (param->open.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "open failed, status %d", p_data->open.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "open success");
|
||||
break;
|
||||
case ESP_GATTC_DIS_SRVC_CMPL_EVT:
|
||||
if (param->dis_srvc_cmpl.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "discover service failed, status %d", param->dis_srvc_cmpl.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "discover service complete conn_id %d", param->dis_srvc_cmpl.conn_id);
|
||||
esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid);
|
||||
break;
|
||||
case ESP_GATTC_CFG_MTU_EVT:
|
||||
if (param->cfg_mtu.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG,"config mtu failed, error status = %x", param->cfg_mtu.status);
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_CFG_MTU_EVT, Status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id);
|
||||
break;
|
||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||
ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
|
||||
ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
|
||||
if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
|
||||
ESP_LOGI(GATTC_TAG, "service found");
|
||||
get_server = true;
|
||||
gl_profile_tab[PROFILE_APP_ID].service_start_handle = p_data->search_res.start_handle;
|
||||
gl_profile_tab[PROFILE_APP_ID].service_end_handle = p_data->search_res.end_handle;
|
||||
ESP_LOGI(GATTC_TAG, "UUID16: %x", p_data->search_res.srvc_id.uuid.uuid.uuid16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT:
|
||||
if (p_data->search_cmpl.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "search service failed, error status = %x", p_data->search_cmpl.status);
|
||||
break;
|
||||
}
|
||||
if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) {
|
||||
ESP_LOGI(GATTC_TAG, "Get service information from remote device");
|
||||
} else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) {
|
||||
ESP_LOGI(GATTC_TAG, "Get service information from flash");
|
||||
} else {
|
||||
ESP_LOGI(GATTC_TAG, "unknown service source");
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_SEARCH_CMPL_EVT");
|
||||
if (get_server){
|
||||
uint16_t count = 0;
|
||||
esp_gatt_status_t status = esp_ble_gattc_get_attr_count( gattc_if,
|
||||
p_data->search_cmpl.conn_id,
|
||||
ESP_GATT_DB_CHARACTERISTIC,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_start_handle,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_end_handle,
|
||||
INVALID_HANDLE,
|
||||
&count);
|
||||
if (status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_attr_count error");
|
||||
break;
|
||||
}
|
||||
|
||||
if (count > 0){
|
||||
char_elem_result = (esp_gattc_char_elem_t *)malloc(sizeof(esp_gattc_char_elem_t) * count);
|
||||
if (!char_elem_result){
|
||||
ESP_LOGE(GATTC_TAG, "gattc no mem");
|
||||
break;
|
||||
}else{
|
||||
status = esp_ble_gattc_get_char_by_uuid( gattc_if,
|
||||
p_data->search_cmpl.conn_id,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_start_handle,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_end_handle,
|
||||
remote_filter_char_uuid,
|
||||
char_elem_result,
|
||||
&count);
|
||||
if (status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_char_by_uuid error");
|
||||
free(char_elem_result);
|
||||
char_elem_result = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (count > 0 && (char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)){
|
||||
gl_profile_tab[PROFILE_APP_ID].char_handle = char_elem_result[0].char_handle;
|
||||
esp_ble_gattc_register_for_notify (gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, char_elem_result[0].char_handle);
|
||||
}
|
||||
}
|
||||
free(char_elem_result);
|
||||
char_elem_result = NULL;
|
||||
}else{
|
||||
ESP_LOGE(GATTC_TAG, "no char found");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT");
|
||||
if (p_data->reg_for_notify.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "REG FOR NOTIFY failed: error status = %d", p_data->reg_for_notify.status);
|
||||
}else{
|
||||
uint16_t count = 0;
|
||||
uint16_t notify_en = 1;
|
||||
esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count( gattc_if,
|
||||
gl_profile_tab[PROFILE_APP_ID].conn_id,
|
||||
ESP_GATT_DB_DESCRIPTOR,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_start_handle,
|
||||
gl_profile_tab[PROFILE_APP_ID].service_end_handle,
|
||||
gl_profile_tab[PROFILE_APP_ID].char_handle,
|
||||
&count);
|
||||
if (ret_status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_attr_count error");
|
||||
}
|
||||
if (count > 0){
|
||||
descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count);
|
||||
if (!descr_elem_result){
|
||||
ESP_LOGE(GATTC_TAG, "malloc error, gattc no mem");
|
||||
}else{
|
||||
ret_status = esp_ble_gattc_get_descr_by_char_handle( gattc_if,
|
||||
gl_profile_tab[PROFILE_APP_ID].conn_id,
|
||||
p_data->reg_for_notify.handle,
|
||||
notify_descr_uuid,
|
||||
descr_elem_result,
|
||||
&count);
|
||||
if (ret_status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_descr_by_char_handle error");
|
||||
}
|
||||
if (count > 0 && descr_elem_result[0].uuid.len == ESP_UUID_LEN_16 && descr_elem_result[0].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG){
|
||||
ret_status = esp_ble_gattc_write_char_descr( gattc_if,
|
||||
gl_profile_tab[PROFILE_APP_ID].conn_id,
|
||||
descr_elem_result[0].handle,
|
||||
sizeof(notify_en),
|
||||
(uint8_t *)¬ify_en,
|
||||
ESP_GATT_WRITE_TYPE_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE);
|
||||
}
|
||||
|
||||
if (ret_status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_write_char_descr error");
|
||||
}
|
||||
|
||||
free(descr_elem_result);
|
||||
descr_elem_result = NULL;
|
||||
}
|
||||
}
|
||||
else{
|
||||
ESP_LOGE(GATTC_TAG, "decsr not found");
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_NOTIFY_EVT:
|
||||
if (p_data->notify.is_notify){
|
||||
ESP_LOGD(GATTC_TAG, "ESP_GATTC_NOTIFY_EVT, receive notify value:");
|
||||
}else{
|
||||
ESP_LOGD(GATTC_TAG, "ESP_GATTC_NOTIFY_EVT, receive indicate value:");
|
||||
}
|
||||
ESP_LOGD(GATTC_TAG, "Received %d bytes of data", p_data->notify.value_len);
|
||||
|
||||
/* Handle latency test notification */
|
||||
latency_test_handle_notify(p_data->notify.value, p_data->notify.value_len);
|
||||
break;
|
||||
case ESP_GATTC_WRITE_DESCR_EVT:
|
||||
if (p_data->write.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "write descr failed, error status = %x", p_data->write.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "write descr success ");
|
||||
|
||||
/* After enabling notification, initialize and start latency test */
|
||||
ESP_LOGI(GATTC_TAG, "Initializing latency test...");
|
||||
latency_test_init(gl_profile_tab[PROFILE_APP_ID].conn_id, gl_profile_tab[PROFILE_APP_ID].char_handle);
|
||||
latency_test_set_gattc_if(gl_profile_tab[PROFILE_APP_ID].gattc_if);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ESP_LOGI(GATTC_TAG, "Starting latency test...");
|
||||
latency_test_start();
|
||||
break;
|
||||
case ESP_GATTC_SRVC_CHG_EVT: {
|
||||
esp_bd_addr_t bda;
|
||||
memcpy(bda, p_data->srvc_chg.remote_bda, sizeof(esp_bd_addr_t));
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_SRVC_CHG_EVT, bd_addr: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_WRITE_CHAR_EVT:
|
||||
if (p_data->write.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "write char failed, error status = %x", p_data->write.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(GATTC_TAG, "write char success ");
|
||||
break;
|
||||
case ESP_GATTC_DISCONNECT_EVT:
|
||||
connect = false;
|
||||
get_server = false;
|
||||
ESP_LOGI(GATTC_TAG, "ESP_GATTC_DISCONNECT_EVT, reason = %d", p_data->disconnect.reason);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
uint8_t *adv_name = NULL;
|
||||
uint8_t adv_name_len = 0;
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
|
||||
uint32_t duration = 30;
|
||||
esp_ble_gap_start_scanning(duration);
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
|
||||
if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(GATTC_TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "scan start success");
|
||||
|
||||
break;
|
||||
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
|
||||
esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
|
||||
switch (scan_result->scan_rst.search_evt) {
|
||||
case ESP_GAP_SEARCH_INQ_RES_EVT:
|
||||
adv_name = esp_ble_resolve_adv_data_by_type(scan_result->scan_rst.ble_adv,
|
||||
scan_result->scan_rst.adv_data_len,
|
||||
ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
|
||||
if (adv_name != NULL) {
|
||||
if (strlen(REMOTE_DEVICE_NAME) == adv_name_len && strncmp((char *)adv_name, REMOTE_DEVICE_NAME, adv_name_len) == 0) {
|
||||
ESP_LOGI(GATTC_TAG, "searched device %s", REMOTE_DEVICE_NAME);
|
||||
if (connect == false) {
|
||||
connect = true;
|
||||
ESP_LOGI(GATTC_TAG, "connect to the remote device.");
|
||||
esp_ble_gap_stop_scanning();
|
||||
esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_SEARCH_INQ_CMPL_EVT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
|
||||
if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
|
||||
ESP_LOGE(GATTC_TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "stop scan successfully");
|
||||
break;
|
||||
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
||||
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
|
||||
ESP_LOGE(GATTC_TAG, "adv stop failed, error status = %x", param->adv_stop_cmpl.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "stop adv successfully");
|
||||
break;
|
||||
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
|
||||
ESP_LOGI(GATTC_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
|
||||
param->update_conn_params.status,
|
||||
param->update_conn_params.min_int,
|
||||
param->update_conn_params.max_int,
|
||||
param->update_conn_params.conn_int,
|
||||
param->update_conn_params.latency,
|
||||
param->update_conn_params.timeout);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_GATTC_REG_EVT) {
|
||||
if (param->reg.status == ESP_GATT_OK) {
|
||||
gl_profile_tab[PROFILE_APP_ID].gattc_if = gattc_if;
|
||||
} else {
|
||||
ESP_LOGI(GATTC_TAG, "reg app failed, app_id %04x, status %d",
|
||||
param->reg.app_id,
|
||||
param->reg.status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
int idx;
|
||||
for (idx = 0; idx < PROFILE_NUM; idx++) {
|
||||
if (gattc_if == ESP_GATT_IF_NONE || gattc_if == gl_profile_tab[idx].gattc_if) {
|
||||
if (gl_profile_tab[idx].gattc_cb) {
|
||||
gl_profile_tab[idx].gattc_cb(event, gattc_if, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(GATTC_TAG, "BLE ACL Latency Test - Central");
|
||||
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTC_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gattc_register_callback(esp_gattc_cb);
|
||||
if(ret){
|
||||
ESP_LOGE(GATTC_TAG, "%s gattc register failed, error code = %x", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_register_callback(esp_gap_cb);
|
||||
if(ret){
|
||||
ESP_LOGE(GATTC_TAG, "%s gap register failed, error code = %x", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gattc_app_register(PROFILE_APP_ID);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTC_TAG, "%s gattc app register failed, error code = %x", __func__, ret);
|
||||
}
|
||||
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(517);
|
||||
if (local_mtu_ret){
|
||||
ESP_LOGE(GATTC_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
|
||||
}
|
||||
|
||||
ESP_LOGI(GATTC_TAG, "Central initialized, scanning for peripheral...");
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_random.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_gattc_api.h"
|
||||
#include "gattc_latency.h"
|
||||
|
||||
static const char *TAG = "LATENCY_TEST";
|
||||
|
||||
/* Global variables */
|
||||
static latency_record_t records[TEST_PACKET_COUNT];
|
||||
static uint16_t test_conn_id = 0;
|
||||
static uint16_t char_handle = 0;
|
||||
static test_packet_t send_packets[TEST_PACKET_COUNT];
|
||||
static bool test_running = false;
|
||||
static bool test_initialized = false;
|
||||
static esp_gatt_if_t test_gattc_if = 0;
|
||||
|
||||
/**
|
||||
* Fill random data
|
||||
*/
|
||||
static void
|
||||
fill_random_data(uint8_t *data, uint16_t len)
|
||||
{
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[i] = esp_random() & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize latency test
|
||||
*/
|
||||
void
|
||||
latency_test_init(uint16_t conn_id, uint16_t handle)
|
||||
{
|
||||
test_conn_id = conn_id;
|
||||
char_handle = handle;
|
||||
test_running = false;
|
||||
test_initialized = true;
|
||||
|
||||
memset(records, 0, sizeof(records));
|
||||
memset(send_packets, 0, sizeof(send_packets));
|
||||
|
||||
ESP_LOGI(TAG, "Latency test initialized, conn_id=%d, handle=%d", conn_id, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set GATT interface
|
||||
*/
|
||||
void
|
||||
latency_test_set_gattc_if(esp_gatt_if_t gattc_if)
|
||||
{
|
||||
test_gattc_if = gattc_if;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send single test packet
|
||||
*/
|
||||
static int
|
||||
send_test_packet(uint16_t seq)
|
||||
{
|
||||
if (char_handle == 0 || test_gattc_if == 0) {
|
||||
ESP_LOGE(TAG, "Test not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Prepare packet */
|
||||
test_packet_t *pkt = &send_packets[seq];
|
||||
pkt->seq_num = seq;
|
||||
fill_random_data(pkt->payload, sizeof(pkt->payload));
|
||||
|
||||
/* Record send time */
|
||||
records[seq].seq = seq;
|
||||
records[seq].send_time_us = esp_timer_get_time();
|
||||
records[seq].received = false;
|
||||
|
||||
/* Send write command (write without response) */
|
||||
esp_err_t ret = esp_ble_gattc_write_char(test_gattc_if,
|
||||
test_conn_id,
|
||||
char_handle,
|
||||
sizeof(test_packet_t),
|
||||
(uint8_t *)pkt,
|
||||
ESP_GATT_WRITE_TYPE_NO_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Write failed: %s", esp_err_to_name(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test task
|
||||
*/
|
||||
static void
|
||||
latency_test_task(void *arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "====================================");
|
||||
ESP_LOGI(TAG, "Starting latency test...");
|
||||
ESP_LOGI(TAG, "Packets: %d, Interval: %d ms", TEST_PACKET_COUNT, TEST_PACKET_INTERVAL_MS);
|
||||
ESP_LOGI(TAG, "====================================");
|
||||
|
||||
test_running = true;
|
||||
|
||||
/* Send all test packets */
|
||||
for (int i = 0; i < TEST_PACKET_COUNT; i++) {
|
||||
int rc = send_test_packet(i);
|
||||
if (rc != 0) {
|
||||
ESP_LOGW(TAG, "Send failed for seq=%d", i);
|
||||
}
|
||||
|
||||
/* Wait interval */
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_PACKET_INTERVAL_MS));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "All packets sent, waiting for responses...");
|
||||
|
||||
/* Wait for all responses */
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
/* Print results */
|
||||
latency_test_print_results();
|
||||
|
||||
test_running = false;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start latency test
|
||||
*/
|
||||
void
|
||||
latency_test_start(void)
|
||||
{
|
||||
if (test_running) {
|
||||
ESP_LOGW(TAG, "Test already running");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_initialized || char_handle == 0) {
|
||||
ESP_LOGE(TAG, "Test not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
xTaskCreate(latency_test_task, "latency_test", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle notification
|
||||
*/
|
||||
void
|
||||
latency_test_handle_notify(uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!test_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record receive time */
|
||||
int64_t recv_time = esp_timer_get_time();
|
||||
|
||||
/* Parse packet */
|
||||
if (len < sizeof(test_packet_t)) {
|
||||
ESP_LOGW(TAG, "Invalid packet size: %d", len);
|
||||
return;
|
||||
}
|
||||
|
||||
test_packet_t *recv_pkt = (test_packet_t *)data;
|
||||
uint16_t seq = recv_pkt->seq_num;
|
||||
|
||||
/* Validate sequence number */
|
||||
if (seq >= TEST_PACKET_COUNT) {
|
||||
ESP_LOGW(TAG, "Invalid seq number: %d", seq);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify data consistency */
|
||||
if (memcmp(recv_pkt, &send_packets[seq], sizeof(test_packet_t)) != 0) {
|
||||
ESP_LOGW(TAG, "Data mismatch for seq=%d", seq);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record receive time */
|
||||
records[seq].recv_time_us = recv_time;
|
||||
records[seq].received = true;
|
||||
|
||||
/* Calculate latency */
|
||||
int64_t rtt_us = recv_time - records[seq].send_time_us;
|
||||
int64_t latency_us = rtt_us / 2;
|
||||
|
||||
/* Print real-time result */
|
||||
printf("SEQ=%3d, RTT=%6lld us, Latency=%6lld us (%.2f ms)\n",
|
||||
seq, rtt_us, latency_us, (float)latency_us / 1000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print statistics
|
||||
*/
|
||||
void
|
||||
latency_test_print_results(void)
|
||||
{
|
||||
int64_t total_latency = 0;
|
||||
int64_t min_latency = INT64_MAX;
|
||||
int64_t max_latency = 0;
|
||||
int valid_count = 0;
|
||||
int lost_count = 0;
|
||||
|
||||
/* Collect statistics */
|
||||
for (int i = 0; i < TEST_PACKET_COUNT; i++) {
|
||||
if (records[i].received) {
|
||||
int64_t rtt = records[i].recv_time_us - records[i].send_time_us;
|
||||
int64_t latency = rtt / 2;
|
||||
|
||||
total_latency += latency;
|
||||
valid_count++;
|
||||
|
||||
if (latency < min_latency) {
|
||||
min_latency = latency;
|
||||
}
|
||||
if (latency > max_latency) {
|
||||
max_latency = latency;
|
||||
}
|
||||
} else {
|
||||
lost_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print results */
|
||||
ESP_LOGI(TAG, "");
|
||||
ESP_LOGI(TAG, "========================================");
|
||||
ESP_LOGI(TAG, " Test Results Summary");
|
||||
ESP_LOGI(TAG, "========================================");
|
||||
ESP_LOGI(TAG, "Total packets: %d", TEST_PACKET_COUNT);
|
||||
ESP_LOGI(TAG, "Received: %d", valid_count);
|
||||
ESP_LOGI(TAG, "Lost: %d (%.1f%%)", lost_count,
|
||||
(float)lost_count * 100.0 / TEST_PACKET_COUNT);
|
||||
|
||||
if (valid_count > 0) {
|
||||
int64_t avg_latency = total_latency / valid_count;
|
||||
|
||||
ESP_LOGI(TAG, "----------------------------------------");
|
||||
ESP_LOGI(TAG, "Average latency: %lld us (%.2f ms)", avg_latency,
|
||||
(float)avg_latency / 1000.0);
|
||||
ESP_LOGI(TAG, "Min latency: %lld us (%.2f ms)", min_latency,
|
||||
(float)min_latency / 1000.0);
|
||||
ESP_LOGI(TAG, "Max latency: %lld us (%.2f ms)", max_latency,
|
||||
(float)max_latency / 1000.0);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "========================================");
|
||||
ESP_LOGI(TAG, "");
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not set
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not set
|
||||
CONFIG_BT_LE_HCI_EVT_BUF_SIZE=257
|
||||
|
||||
# XTAL Freq Config
|
||||
CONFIG_XTAL_FREQ_26=y
|
||||
CONFIG_XTAL_FREQ=26
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_acl_latency_periph)
|
||||
@@ -0,0 +1,124 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-IDF BLE ACL Latency Test - Peripheral
|
||||
|
||||
This example demonstrates how to measure BLE ACL (Asynchronous Connection-Less) link latency. The peripheral acts as a GATT server that echoes back any data written to it, allowing the central device to measure round-trip time (RTT) and calculate one-way latency.
|
||||
|
||||
This demo should be used together with the `cent` (central) example.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. The peripheral advertises with the device name `ESP_ACL_LATENCY`
|
||||
2. When a central device connects, the peripheral accepts the connection
|
||||
3. The peripheral provides a GATT service with a characteristic that supports both write and notify
|
||||
4. When data is written to the characteristic, the peripheral immediately echoes it back via notification
|
||||
5. The central measures the time between sending and receiving to calculate RTT and latency
|
||||
|
||||
## Test Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Central │ │ Peripheral │
|
||||
│ (GATT Client)│ │ (GATT Server)│
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ │ Advertising
|
||||
│ │ "ESP_ACL_LATENCY"
|
||||
│ Scan & Connect │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Connection Established │
|
||||
│ <─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ MTU Exchange, Service Discovery │
|
||||
│ <─────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ──────────── Latency Test ───────────── │
|
||||
│ │
|
||||
│ Write [SEQ=N, 242 bytes] │
|
||||
│ ─────────────────────────────────────────> │
|
||||
│ ┌───────┴───────┐
|
||||
│ │ Echo the same │
|
||||
│ │ data back via │
|
||||
│ │ Notification │
|
||||
│ └───────┬───────┘
|
||||
│ Notification [SEQ=N, 242 bytes] │
|
||||
│ <───────────────────────────────────────── │
|
||||
│ │
|
||||
│ ... Repeat for 100 packets ... │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ Central │ │ Peripheral │
|
||||
└──────────────┘ └──────────────┘
|
||||
|
||||
┌─────────────────────────────────┐
|
||||
│ Latency Calculation │
|
||||
├─────────────────────────────────┤
|
||||
│ RTT = recv_time - send_time │
|
||||
│ One-way Latency = RTT / 2 │
|
||||
│ Typical Result: 6-10 ms │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* Two development boards with supported SoC (e.g., ESP32-C3-DevKitC, ESP32-DevKitC, etc.)
|
||||
* Two USB cables for power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information.
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board:
|
||||
|
||||
```bash
|
||||
idf.py -p PORT flash
|
||||
```
|
||||
|
||||
(Replace PORT with the serial port name, e.g., `/dev/ttyUSB0` on Linux or `COM3` on Windows)
|
||||
|
||||
### Monitor
|
||||
|
||||
Run `idf.py -p PORT monitor` to view the serial output.
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (362) BLE_ACL_LATENCY_PERIPH: BLE ACL Latency Test - Peripheral
|
||||
I (372) phy_init: phy_version 310,dde1ba9,Jun 4 2024,16:38:11
|
||||
I (432) BLE_ACL_LATENCY_PERIPH: GATT server register, status=0, app_id=0
|
||||
I (442) BLE_ACL_LATENCY_PERIPH: Create attribute table successfully, the number handle=4
|
||||
I (442) BLE_ACL_LATENCY_PERIPH: SERVICE_START_EVT, status=0, service_handle=40
|
||||
I (452) BLE_ACL_LATENCY_PERIPH: Advertising started
|
||||
I (462) BLE_ACL_LATENCY_PERIPH: Peripheral ready, waiting for connection...
|
||||
I (5532) BLE_ACL_LATENCY_PERIPH: ESP_GATTS_CONNECT_EVT, conn_id=0, remote 7c:df:a1:66:a6:00
|
||||
I (5892) BLE_ACL_LATENCY_PERIPH: MTU exchange, MTU=517
|
||||
I (5912) BLE_ACL_LATENCY_PERIPH: Connection params updated: status=0, conn_int=6, latency=0, timeout=500
|
||||
```
|
||||
|
||||
## GATT Service Structure
|
||||
|
||||
| Attribute | UUID | Properties | Description |
|
||||
|-----------|--------|-------------------|---------------------------------|
|
||||
| Service | 0x1234 | - | Latency test service |
|
||||
| Char | 0x5678 | Write, Notify | Write data, receive echo back |
|
||||
| CCCD | 0x2902 | Read, Write | Client Characteristic Config |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "gatts_latency_demo.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#ifndef H_GATTS_LATENCY_
|
||||
#define H_GATTS_LATENCY_
|
||||
|
||||
#include "esp_gatts_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Service UUID */
|
||||
#define LATENCY_SERVICE_UUID 0x1234
|
||||
#define LATENCY_CHAR_UUID 0x5678
|
||||
|
||||
/* Profile ID */
|
||||
#define PROFILE_APP_ID 0
|
||||
|
||||
/* Handle table */
|
||||
enum {
|
||||
LATENCY_IDX_SVC,
|
||||
LATENCY_IDX_CHAR,
|
||||
LATENCY_IDX_CHAR_VAL,
|
||||
LATENCY_IDX_CHAR_CFG,
|
||||
|
||||
LATENCY_IDX_NB,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_GATTS_LATENCY_ */
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_bt.h"
|
||||
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatts_api.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
#include "gatts_latency.h"
|
||||
|
||||
#define GATTS_TAG "BLE_ACL_LATENCY_PERIPH"
|
||||
|
||||
#define DEVICE_NAME "ESP_ACL_LATENCY"
|
||||
#define GATTS_NUM_HANDLE 4
|
||||
|
||||
static uint8_t adv_config_done = 0;
|
||||
#define adv_config_flag (1 << 0)
|
||||
#define scan_rsp_config_flag (1 << 1)
|
||||
|
||||
/* Advertisement data */
|
||||
static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = false,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), // 7.5ms (minimum)
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), // 20ms
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
.service_data_len = 0,
|
||||
.p_service_data = NULL,
|
||||
.service_uuid_len = 0,
|
||||
.p_service_uuid = NULL,
|
||||
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
|
||||
};
|
||||
|
||||
/* Scan response data */
|
||||
static esp_ble_adv_data_t scan_rsp_data = {
|
||||
.set_scan_rsp = true,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
.service_data_len = 0,
|
||||
.p_service_data = NULL,
|
||||
.service_uuid_len = 0,
|
||||
.p_service_uuid = NULL,
|
||||
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20), // 20ms
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40), // 40ms
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
struct gatts_profile_inst {
|
||||
esp_gatts_cb_t gatts_cb;
|
||||
uint16_t gatts_if;
|
||||
uint16_t app_id;
|
||||
uint16_t conn_id;
|
||||
uint16_t service_handle;
|
||||
esp_gatt_srvc_id_t service_id;
|
||||
uint16_t char_handle;
|
||||
esp_bt_uuid_t char_uuid;
|
||||
esp_gatt_perm_t perm;
|
||||
esp_gatt_char_prop_t property;
|
||||
uint16_t descr_handle;
|
||||
esp_bt_uuid_t descr_uuid;
|
||||
};
|
||||
|
||||
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
|
||||
|
||||
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
|
||||
#define PROFILE_NUM 1
|
||||
#define PROFILE_APP_IDX 0
|
||||
|
||||
static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
|
||||
[PROFILE_APP_IDX] = {
|
||||
.gatts_cb = gatts_profile_event_handler,
|
||||
.gatts_if = ESP_GATT_IF_NONE,
|
||||
},
|
||||
};
|
||||
|
||||
/* Service */
|
||||
static const uint16_t GATTS_SERVICE_UUID = LATENCY_SERVICE_UUID;
|
||||
static const uint16_t GATTS_CHAR_UUID = LATENCY_CHAR_UUID;
|
||||
|
||||
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
|
||||
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
|
||||
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
|
||||
static const uint8_t char_prop_write_notify = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
|
||||
static uint8_t char_ccc[2] = {0x00, 0x00};
|
||||
|
||||
/* Full Database Description - Used to add attributes into the database */
|
||||
static const esp_gatts_attr_db_t gatt_db[LATENCY_IDX_NB] =
|
||||
{
|
||||
/* Service Declaration */
|
||||
[LATENCY_IDX_SVC] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
|
||||
sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID), (uint8_t *)&GATTS_SERVICE_UUID}},
|
||||
|
||||
/* Characteristic Declaration */
|
||||
[LATENCY_IDX_CHAR] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
|
||||
sizeof(uint8_t), sizeof(uint8_t), (uint8_t *)&char_prop_write_notify}},
|
||||
|
||||
/* Characteristic Value */
|
||||
[LATENCY_IDX_CHAR_VAL] =
|
||||
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
|
||||
512, 0, NULL}},
|
||||
|
||||
/* Client Characteristic Configuration Descriptor */
|
||||
[LATENCY_IDX_CHAR_CFG] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
|
||||
sizeof(uint16_t), sizeof(char_ccc), (uint8_t *)char_ccc}},
|
||||
};
|
||||
|
||||
static uint16_t handle_table[LATENCY_IDX_NB];
|
||||
|
||||
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
||||
adv_config_done &= (~adv_config_flag);
|
||||
if (adv_config_done == 0){
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
||||
adv_config_done &= (~scan_rsp_config_flag);
|
||||
if (adv_config_done == 0){
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
|
||||
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(GATTS_TAG, "Advertising start failed");
|
||||
} else {
|
||||
ESP_LOGI(GATTS_TAG, "Advertising started");
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
||||
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(GATTS_TAG, "Advertising stop failed");
|
||||
} else {
|
||||
ESP_LOGI(GATTS_TAG, "Advertising stopped");
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "Connection params updated: status=%d, conn_int=%d, latency=%d, timeout=%d",
|
||||
param->update_conn_params.status,
|
||||
param->update_conn_params.conn_int,
|
||||
param->update_conn_params.latency,
|
||||
param->update_conn_params.timeout);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GATTS_REG_EVT:{
|
||||
ESP_LOGI(GATTS_TAG, "GATT server register, status=%d, app_id=%d", param->reg.status, param->reg.app_id);
|
||||
gl_profile_tab[PROFILE_APP_IDX].service_id.is_primary = true;
|
||||
gl_profile_tab[PROFILE_APP_IDX].service_id.id.inst_id = 0x00;
|
||||
gl_profile_tab[PROFILE_APP_IDX].service_id.id.uuid.len = ESP_UUID_LEN_16;
|
||||
gl_profile_tab[PROFILE_APP_IDX].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID;
|
||||
|
||||
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(DEVICE_NAME);
|
||||
if (set_dev_name_ret){
|
||||
ESP_LOGE(GATTS_TAG, "Set device name failed, error code = %x", set_dev_name_ret);
|
||||
}
|
||||
|
||||
esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTS_TAG, "Config adv data failed, error code = %x", ret);
|
||||
}
|
||||
adv_config_done |= adv_config_flag;
|
||||
|
||||
ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTS_TAG, "Config scan response data failed, error code = %x", ret);
|
||||
}
|
||||
adv_config_done |= scan_rsp_config_flag;
|
||||
|
||||
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, LATENCY_IDX_NB, 0);
|
||||
if (create_attr_ret){
|
||||
ESP_LOGE(GATTS_TAG, "Create attr table failed, error code = %x", create_attr_ret);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_READ_EVT:
|
||||
ESP_LOGD(GATTS_TAG, "ESP_GATTS_READ_EVT");
|
||||
break;
|
||||
case ESP_GATTS_WRITE_EVT:
|
||||
if (!param->write.is_prep){
|
||||
ESP_LOGD(GATTS_TAG, "GATT_WRITE_EVT, handle=%d, value len=%d", param->write.handle, param->write.len);
|
||||
|
||||
if (handle_table[LATENCY_IDX_CHAR_VAL] == param->write.handle) {
|
||||
/* Echo the data back via notification */
|
||||
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, handle_table[LATENCY_IDX_CHAR_VAL],
|
||||
param->write.len, param->write.value, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_EXEC_WRITE_EVT:
|
||||
case ESP_GATTS_MTU_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "MTU exchange, MTU=%d", param->mtu.mtu);
|
||||
break;
|
||||
case ESP_GATTS_CONF_EVT:
|
||||
break;
|
||||
case ESP_GATTS_START_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status=%d, service_handle=%d", param->start.status, param->start.service_handle);
|
||||
break;
|
||||
case ESP_GATTS_CONNECT_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "ESP_GATTS_CONNECT_EVT, conn_id=%d, remote "ESP_BD_ADDR_STR"",
|
||||
param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
|
||||
gl_profile_tab[PROFILE_APP_IDX].conn_id = param->connect.conn_id;
|
||||
break;
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
ESP_LOGI(GATTS_TAG, "ESP_GATTS_DISCONNECT_EVT, reason=0x%x", param->disconnect.reason);
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
break;
|
||||
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
|
||||
if (param->add_attr_tab.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTS_TAG, "Create attribute table failed, error code=0x%x", param->add_attr_tab.status);
|
||||
}
|
||||
else if (param->add_attr_tab.num_handle != LATENCY_IDX_NB){
|
||||
ESP_LOGE(GATTS_TAG, "Create attribute table abnormally, num_handle (%d) \
|
||||
doesn't equal to LATENCY_IDX_NB(%d)", param->add_attr_tab.num_handle, LATENCY_IDX_NB);
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(GATTS_TAG, "Create attribute table successfully, the number handle=%d",param->add_attr_tab.num_handle);
|
||||
memcpy(handle_table, param->add_attr_tab.handles, sizeof(handle_table));
|
||||
esp_ble_gatts_start_service(handle_table[LATENCY_IDX_SVC]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_STOP_EVT:
|
||||
case ESP_GATTS_OPEN_EVT:
|
||||
case ESP_GATTS_CANCEL_OPEN_EVT:
|
||||
case ESP_GATTS_CLOSE_EVT:
|
||||
case ESP_GATTS_LISTEN_EVT:
|
||||
case ESP_GATTS_CONGEST_EVT:
|
||||
case ESP_GATTS_UNREG_EVT:
|
||||
case ESP_GATTS_DELETE_EVT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_GATTS_REG_EVT) {
|
||||
if (param->reg.status == ESP_GATT_OK) {
|
||||
gl_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
|
||||
} else {
|
||||
ESP_LOGE(GATTS_TAG, "Reg app failed, app_id %04x, status %d",
|
||||
param->reg.app_id,
|
||||
param->reg.status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
do {
|
||||
int idx;
|
||||
for (idx = 0; idx < PROFILE_NUM; idx++) {
|
||||
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == gl_profile_tab[idx].gatts_if) {
|
||||
if (gl_profile_tab[idx].gatts_cb) {
|
||||
gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(GATTS_TAG, "BLE ACL Latency Test - Peripheral");
|
||||
|
||||
/* Initialize NVS */
|
||||
ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gatts_register_callback(gatts_event_handler);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTS_TAG, "gatts register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTS_TAG, "gap register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gatts_app_register(PROFILE_APP_ID);
|
||||
if (ret){
|
||||
ESP_LOGE(GATTS_TAG, "gatts app register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(517);
|
||||
if (local_mtu_ret){
|
||||
ESP_LOGE(GATTS_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
|
||||
}
|
||||
|
||||
ESP_LOGI(GATTS_TAG, "Peripheral ready, waiting for connection...");
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not set
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not set
|
||||
CONFIG_BT_LE_HCI_EVT_BUF_SIZE=257
|
||||
|
||||
# XTAL Freq Config
|
||||
CONFIG_XTAL_FREQ_26=y
|
||||
CONFIG_XTAL_FREQ=26
|
||||
@@ -5,6 +5,55 @@
|
||||
|
||||
The purpose of the Apple Notification Center Service (ANCS) is to give Bluetooth accessories (that connect to iOS devices through a Bluetooth low-energy link) a simple and convenient way to access many kinds of notifications that are generated on iOS devices.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ ESP32 │ │ iOS Device │
|
||||
│ (ANCS Client)│ │ (ANCS Server)│
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Connection ─────────── │
|
||||
│ │
|
||||
│ 1. Start Advertising │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 2. iOS connects & pairs │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Service Discovery ─────────── │
|
||||
│ │
|
||||
│ 3. Discover ANCS Service │
|
||||
│ (UUID: 7905F431-B5CE-4E99-A40F-4B1E122D00D0) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 4. Subscribe to Notification Source │
|
||||
│ (UUID: 9FBF120D-6301-42D9-8C58-25E699A21DBD) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 5. Subscribe to Data Source │
|
||||
│ (UUID: 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Notification Flow ─────────── │
|
||||
│ │
|
||||
│ 6. New notification on iOS │
|
||||
│ (Call, SMS, Email, App, etc.) │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ 7. Request notification details │
|
||||
│ (Write to Control Point) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 8. Receive notification attributes │
|
||||
│ (Title, Message, App, etc.) │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ ESP32 │ │ iOS Device │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -83,8 +83,8 @@ static uint8_t hidd_service_uuid128[] = {
|
||||
static esp_ble_adv_data_t adv_config = {
|
||||
.set_scan_rsp = false,
|
||||
.include_txpower = false,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), //slave connection max interval
|
||||
.appearance = ESP_BLE_APPEARANCE_GENERIC_HID,
|
||||
.service_uuid_len = sizeof(hidd_service_uuid128),
|
||||
.p_service_uuid = hidd_service_uuid128,
|
||||
@@ -99,8 +99,8 @@ static esp_ble_adv_data_t scan_rsp_config = {
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x100,
|
||||
.adv_int_max = 0x100,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(160),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(160),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -5,6 +5,52 @@
|
||||
|
||||
This example is to test the Bluetooth compatibility and mobile phones.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ ESP32 BLE │ │ Mobile Phone │
|
||||
│ (Compatibility) │ │ (LightBlue App) │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ 1. Initialize BLE │
|
||||
│ 2. Create GATT Services │
|
||||
│ 3. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Test Scenarios ─────────── │
|
||||
│ │
|
||||
│ Scan & Discover │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ │
|
||||
│ Connection Request │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ │
|
||||
│ Service Discovery │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ │
|
||||
│ Read Characteristic │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ Read Response │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ │
|
||||
│ Write Characteristic │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ Write Confirmation │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ │
|
||||
│ Enable Notification │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ Notification Data │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ │
|
||||
│ Disconnection │
|
||||
│ <═══════════════════════════════════════════>│
|
||||
│ │
|
||||
┌────────┴─────────┐ ┌────────┴─────────┐
|
||||
│ ESP32 BLE │ │ Mobile Phone │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -101,8 +101,8 @@ static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x20,
|
||||
.max_interval = 0x40,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(40),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(80),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //test_manufacturer,
|
||||
@@ -118,8 +118,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
.set_scan_rsp = true,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x20,
|
||||
.max_interval = 0x40,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(40),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(80),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -132,8 +132,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
#endif /* CONFIG_SET_RAW_ADV_DATA */
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x40,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -5,11 +5,43 @@
|
||||
|
||||
This example demonstrates Eddystone-compatible BLE scanning of eddystone frame, including UID and URL.
|
||||
|
||||
Eddystone is an open beacon protocol specification from Google aimed at improving “proximity-based experiences”
|
||||
Eddystone is an open beacon protocol specification from Google aimed at improving "proximity-based experiences"
|
||||
with support for both Android and iOS smart device platforms.
|
||||
|
||||
Learn more on [Beacons](https://developers.google.com/nearby/notifications/get-started) and [Eddystone](https://github.com/google/eddystone).
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Eddystone Sender │ │Eddystone Receiver│
|
||||
│ (Advertiser) │ │ (this example) │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ Broadcasting Eddystone Frames │ 1. Initialize BLE
|
||||
│ │ 2. Start Scanning
|
||||
│ │
|
||||
│ ─────────── Scanning ─────────── │
|
||||
│ │
|
||||
│ Eddystone UID Frame │
|
||||
│ ═══════════════════════════════════════════>│
|
||||
│ │ 3. Detect Eddystone
|
||||
│ │ 4. Parse UID Frame:
|
||||
│ │ - Namespace ID
|
||||
│ │ - Instance ID
|
||||
│ │ - RSSI
|
||||
│ │
|
||||
│ Eddystone URL Frame │
|
||||
│ ═══════════════════════════════════════════>│
|
||||
│ │ 5. Parse URL Frame:
|
||||
│ │ - Decode URL
|
||||
│ │ - TX Power
|
||||
│ │
|
||||
┌────────┴─────────┐ ┌────────┴─────────┐
|
||||
│ Eddystone Sender │ │Eddystone Receiver│
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -39,8 +39,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
|
||||
@@ -5,11 +5,43 @@
|
||||
|
||||
This example demonstrates Eddystone-compatible BLE sending of eddystone frame, including UID and URL and TLM.
|
||||
|
||||
Eddystone is an open beacon protocol specification from Google aimed at improving “proximity-based experiences”
|
||||
Eddystone is an open beacon protocol specification from Google aimed at improving "proximity-based experiences"
|
||||
with support for both Android and iOS smart device platforms.
|
||||
|
||||
Learn more on [Beacons](https://developers.google.com/nearby/notifications/get-started) and [Eddystone](https://github.com/google/eddystone).
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Eddystone Sender │ │ Eddystone Receiver│
|
||||
│ (Advertiser) │ │ (Scanner) │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ 1. Initialize BLE │
|
||||
│ 2. Configure Eddystone Frame: │
|
||||
│ - UID Frame (Namespace + Instance) │
|
||||
│ - URL Frame (Encoded URL) │
|
||||
│ - TLM Frame (Telemetry Data) │
|
||||
│ 3. Set Raw Advertising Data │
|
||||
│ 4. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Broadcasting ─────────── │
|
||||
│ │
|
||||
│ Eddystone Advertisement Packet │
|
||||
│ ═══════════════════════════════════════════>│
|
||||
│ (Broadcast periodically) │
|
||||
│ │
|
||||
│ │ Parse Frame:
|
||||
│ │ - UID: Namespace ID
|
||||
│ │ - URL: Decoded URL
|
||||
│ │ - TLM: Battery, Temp
|
||||
│ │
|
||||
┌────────┴─────────┐ ┌────────┴─────────┐
|
||||
│ Eddystone Sender │ │ Eddystone Receiver│
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -36,8 +36,8 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* par
|
||||
static void eddystone_send_raw(const esp_eddystone_result_t *res);
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -13,6 +13,54 @@ This example implement a BLE HID device profile related functions, in which the
|
||||
Users can choose different reports according to their own application scenarios.
|
||||
BLE HID profile inheritance and USB HID class.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ BLE HID │ │ Host │
|
||||
│ Device │ │ (PC/Phone) │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Initialization ─────────── │
|
||||
│ │
|
||||
│ 1. Create HID Service │
|
||||
│ - HID Information Char │
|
||||
│ - Report Map Char │
|
||||
│ - Report Chars (Mouse/Keyboard/Consumer) │
|
||||
│ - HID Control Point Char │
|
||||
│ 2. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Connection & Pairing ─────────── │
|
||||
│ │
|
||||
│ Scan & Connect │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Pairing (Bonding) │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ Enable Report Notification │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── HID Data Transfer ─────────── │
|
||||
│ │
|
||||
│ Send Keyboard Report │
|
||||
│ (Key Press/Release) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Send Mouse Report │
|
||||
│ (X/Y Movement, Buttons) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Send Consumer Report │
|
||||
│ (Volume +/-, Media Control) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ BLE HID │ │ Host │
|
||||
│ Device │ │ (PC/Phone) │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -67,8 +67,8 @@ static esp_ble_adv_data_t hidd_adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), //slave connection max interval
|
||||
.appearance = 0x03c0, //HID Generic,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
@@ -80,8 +80,8 @@ static esp_ble_adv_data_t hidd_adv_data = {
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t hidd_adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x30,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(30),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
//.peer_addr =
|
||||
|
||||
@@ -5,6 +5,61 @@
|
||||
|
||||
From welcoming people as they arrive at a sporting event to providing information about a nearby museum exhibit, iBeacon opens a new world of possibilities for location awareness, and countless opportunities for interactivity between iOS devices and iBeacon hardware.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ iBeacon System │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ iBeacon Sender │ │ iBeacon Receiver │
|
||||
│ (Advertiser) │ │ (Scanner) │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ ─────────── Sender Operation ─────────── │
|
||||
│ │
|
||||
│ 1. Initialize BLE │
|
||||
│ 2. Configure iBeacon Data: │
|
||||
│ - Proximity UUID (16 bytes) │
|
||||
│ - Major ID (2 bytes) │
|
||||
│ - Minor ID (2 bytes) │
|
||||
│ - TX Power (1 byte) │
|
||||
│ 3. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Broadcasting ─────────── │
|
||||
│ │
|
||||
│ iBeacon Advertisement Packet │
|
||||
│ ═══════════════════════════════════════════>│
|
||||
│ (Broadcast every ~100ms) │
|
||||
│ │
|
||||
│ │ ─── Receiver ───
|
||||
│ │
|
||||
│ │ 1. Start Scan
|
||||
│ │ 2. Receive Adv
|
||||
│ │ 3. Parse iBeacon:
|
||||
│ │ - UUID
|
||||
│ │ - Major/Minor
|
||||
│ │ - RSSI
|
||||
│ │ 4. Calculate
|
||||
│ │ Distance
|
||||
│ │
|
||||
┌────────┴─────────┐ ┌────────┴─────────┐
|
||||
│ iBeacon Sender │ │ iBeacon Receiver │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
|
||||
|
||||
┌─────────────────────────────────┐
|
||||
│ iBeacon Packet Structure │
|
||||
├─────────────────────────────────┤
|
||||
│ Prefix: 9 bytes │
|
||||
│ UUID: 16 bytes │
|
||||
│ Major: 2 bytes │
|
||||
│ Minor: 2 bytes │
|
||||
│ TX Power: 1 byte │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -43,15 +43,15 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
#elif (IBEACON_MODE == IBEACON_SENDER)
|
||||
static esp_ble_adv_params_t ble_adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_NONCONN_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -7,6 +7,52 @@
|
||||
|
||||
**This example relies on the BLE controller. please use the chip modules listed under Supported Targets.**
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ BLE Multi-Connection Central │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌───────────────────┐
|
||||
│ Multi-Conn Cent │
|
||||
│ (GATTC + GATTS) │
|
||||
└─────────┬─────────┘
|
||||
│
|
||||
│ 1. Initialize GATT Client & Server
|
||||
│ 2. Set Random Address
|
||||
│ 3. Start Scanning
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ Scan for Peripherals │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Found peripheral?
|
||||
│
|
||||
├───────────────────┬───────────────────┬───────────────────┐
|
||||
▼ ▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ...
|
||||
│ Peripheral 1 │ │ Peripheral 2 │ │ Peripheral 3 │
|
||||
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
|
||||
│ │ │
|
||||
│ ─────────── For Each Peripheral ───────────
|
||||
│
|
||||
│ 4. Stop Scanning
|
||||
│ 5. Create Connection
|
||||
│ 6. Update Scheduling Length
|
||||
│ 7. Connection Established
|
||||
│ 8. Add to Peer List
|
||||
│ 9. Change Random Address
|
||||
│ 10. Resume Scanning
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ All peripherals connected (up to CONFIG limit) │
|
||||
│ Maintain multiple connections │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+7
-7
@@ -101,7 +101,7 @@ const static esp_ble_conn_params_t phy_1m_conn_params = {
|
||||
.interval_min = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.interval_max = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = BLE_PREF_CE_LEN,
|
||||
.max_ce_len = BLE_PREF_CE_LEN,
|
||||
};
|
||||
@@ -113,7 +113,7 @@ const static esp_ble_conn_params_t phy_2m_conn_params = {
|
||||
.interval_min = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.interval_max = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = BLE_PREF_CE_LEN,
|
||||
.max_ce_len = BLE_PREF_CE_LEN,
|
||||
};
|
||||
@@ -124,7 +124,7 @@ const static esp_ble_conn_params_t phy_coded_conn_params = {
|
||||
.interval_min = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.interval_max = BLE_PREF_CONN_ITVL_MS * 1000 / 1250,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = BLE_PREF_CE_LEN,
|
||||
.max_ce_len = BLE_PREF_CE_LEN,
|
||||
};
|
||||
@@ -160,8 +160,8 @@ struct gatts_profile_inst
|
||||
|
||||
#if (BLE50_SUPPORTED == 0)
|
||||
esp_ble_adv_params_t legacy_adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x20,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
@@ -171,8 +171,8 @@ esp_ble_adv_params_t legacy_adv_params = {
|
||||
#else
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
|
||||
.interval_min = 0x20,
|
||||
.interval_max = 0x20,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
|
||||
@@ -7,6 +7,45 @@
|
||||
|
||||
**This example relies on the BLE controller. Please use the chip modules listed under Supported Targets.**
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ BLE Multi-Connection Peripheral │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ Multi-Conn Prph │ │ Centrals │
|
||||
│ (GATT Server) │ │ (1, 2, 3, ...) │
|
||||
└─────────┬─────────┘ └─────────┬─────────┘
|
||||
│ │
|
||||
│ 1. Initialize GATT Server │
|
||||
│ 2. Create Service │
|
||||
│ 3. Set Random Address │
|
||||
│ 4. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Connection Loop ───────────
|
||||
│ │
|
||||
│ Central 1 connects │
|
||||
│ <───────────────────────────│
|
||||
│ │
|
||||
│ 5. Stop Advertising │
|
||||
│ 6. Connection Established │
|
||||
│ 7. Change Random Address │
|
||||
│ 8. Restart Advertising │
|
||||
│ │
|
||||
│ Central 2 connects │
|
||||
│ <───────────────────────────│
|
||||
│ │
|
||||
│ ... Repeat for each Central ...
|
||||
│ │
|
||||
▼ │
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ Maintain multiple connections simultaneously │
|
||||
│ (Limited by CONFIG_BT_ACL_CONNECTIONS) │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+4
-4
@@ -68,8 +68,8 @@ static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
|
||||
.interval_min = 0x20,
|
||||
.interval_max = 0x20,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -82,8 +82,8 @@ esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
};
|
||||
#else
|
||||
static esp_ble_adv_params_t legacy_adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -9,6 +9,71 @@
|
||||
|
||||
This vendor-specific custom profile is implemented in [spp_client_demo.c](../ble_spp_client/main/spp_client_demo.c) and [spp_server_demo.c](../ble_spp_server/main/ble_spp_server_demo.c).
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ BLE SPP Data Flow │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
SPP Client SPP Server
|
||||
┌───────────┐ ┌───────────┐
|
||||
│ UART │ │ UART │
|
||||
│ Terminal │ │ Terminal │
|
||||
└─────┬─────┘ └─────┬─────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────┐ ┌───────────┐
|
||||
│ uart_task │ │ uart_task │
|
||||
└─────┬─────┘ └─────┬─────┘
|
||||
│ │
|
||||
│ ─────────── Connection Phase ─────────── │
|
||||
│ │
|
||||
│ 1. Scan for SPP Server │ Advertising
|
||||
│ ───────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 2. Connect │
|
||||
│ ───────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 3. MTU Exchange (200 bytes) │
|
||||
│ <────────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ 4. Service Discovery │
|
||||
│ ───────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 5. Enable Notification (CCCD) │
|
||||
│ ───────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Data Exchange ─────────── │
|
||||
│ │
|
||||
│ UART Input ──> WriteNoRsp (SPP_DATA_RECV_CHAR) │
|
||||
│ ───────────────────────────────────────────────────> │──> UART Output
|
||||
│ │
|
||||
│ UART Output <── Notification (SPP_DATA_NOTIFY_CHAR) │
|
||||
│ <─────────────────────────────────────────────────── │<── UART Input
|
||||
│ │
|
||||
┌─────┴─────┐ ┌─────┴─────┐
|
||||
│ SPP Client│ │SPP Server │
|
||||
└───────────┘ └───────────┘
|
||||
|
||||
|
||||
┌─────────────────────────────────┐
|
||||
│ SPP Characteristics │
|
||||
├─────────────────────────────────┤
|
||||
│ SPP_DATA_RECV (0xABF1) │
|
||||
│ - Client writes data here │
|
||||
│ │
|
||||
│ SPP_DATA_NOTIFY (0xABF2) │
|
||||
│ - Server sends data here │
|
||||
│ │
|
||||
│ SPP_COMMAND (0xABF3) │
|
||||
│ - Command channel │
|
||||
│ │
|
||||
│ SPP_STATUS (0xABF4) │
|
||||
│ - Status notification │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -89,8 +89,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
@@ -255,7 +255,7 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
phy_1m_conn_params.interval_max = 32;
|
||||
phy_1m_conn_params.interval_min = 32;
|
||||
phy_1m_conn_params.latency = 0;
|
||||
phy_1m_conn_params.supervision_timeout = 600;
|
||||
phy_1m_conn_params.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000);
|
||||
esp_ble_gatt_creat_conn_params_t creat_conn_params = {0};
|
||||
memcpy(&creat_conn_params.remote_bda, scan_result->scan_rst.bda,ESP_BD_ADDR_LEN);
|
||||
creat_conn_params.remote_addr_type = scan_result->scan_rst.ble_addr_type;
|
||||
|
||||
@@ -5,6 +5,42 @@
|
||||
|
||||
For description of this application please refer to [ESP-IDF GATT CLIENT SPP Example](../ble_spp_client/README.md)
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
SPP Server SPP Client
|
||||
┌───────────┐ ┌───────────┐
|
||||
│ UART │ │ UART │
|
||||
│ Terminal │ │ Terminal │
|
||||
└─────┬─────┘ └─────┬─────┘
|
||||
│ │
|
||||
│ ─────────── Initialization ─────────── │
|
||||
│ │
|
||||
│ 1. Create SPP Service (UUID: 0xABF0) │
|
||||
│ 2. Add Characteristics │
|
||||
│ 3. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Connection ─────────── │
|
||||
│ │
|
||||
│ Scan & Connect │
|
||||
│ <─────────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Connection Established │
|
||||
│ ─────────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ ─────────── Data Exchange ─────────── │
|
||||
│ │
|
||||
│ UART Input ──> Notification (SPP_DATA_NOTIFY_CHAR) │
|
||||
│ ─────────────────────────────────────────────────────>│──> UART Output
|
||||
│ │
|
||||
│ UART Output <── WriteNoRsp (SPP_DATA_RECV_CHAR) │
|
||||
│ <─────────────────────────────────────────────────── │<── UART Input
|
||||
│ │
|
||||
┌─────┴─────┐ ┌─────┴─────┐
|
||||
│SPP Server │ │ SPP Client│
|
||||
└───────────┘ └───────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -52,11 +52,11 @@ static const uint16_t spp_service_uuid = 0xABF0;
|
||||
|
||||
static const uint8_t spp_adv_data[23] = {
|
||||
/* Flags */
|
||||
0x02,0x01,0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
/* Complete List of 16-bit Service Class UUIDs */
|
||||
0x03,0x03,0xF0,0xAB,
|
||||
0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xF0, 0xAB,
|
||||
/* Complete Local Name in advertising */
|
||||
0x0F,0x09, 'E', 'S', 'P', '_', 'S', 'P', 'P', '_', 'S', 'E', 'R','V', 'E', 'R'
|
||||
0x0F, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'S', 'P', 'P', '_', 'S', 'E', 'R','V', 'E', 'R'
|
||||
};
|
||||
|
||||
static uint16_t spp_mtu_size = SPP_GATT_MTU_SIZE;
|
||||
@@ -79,8 +79,8 @@ static esp_bd_addr_t spp_remote_bda = {0x0,};
|
||||
static uint16_t spp_handle_table[SPP_IDX_NB];
|
||||
|
||||
static esp_ble_adv_params_t spp_adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -6,6 +6,49 @@
|
||||
This is the demo used to test the BLE throughput, this demo should used with throughput server demo together.
|
||||
The throughput of BLE can up to 720-767 Kbps between to ESP32 board.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Throughput │ │ Throughput │
|
||||
│ Client │ │ Server │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Connection Setup ─────────── │
|
||||
│ │
|
||||
│ 1. Scan for "THROUGHPUT_DEMO" │ Advertising
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 2. Connect │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 3. MTU Exchange (517 bytes) │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ 4. Enable Notification │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Throughput Test ─────────── │
|
||||
│ │
|
||||
│ Mode 1: Notify Test (Server → Client) │
|
||||
│ <═══════════════════════════════════════════════ │
|
||||
│ Continuous notifications (514 bytes/packet) │
|
||||
│ │
|
||||
│ Mode 2: Write Test (Client → Server) │
|
||||
│ ═══════════════════════════════════════════════> │
|
||||
│ Continuous writes (514 bytes/packet) │
|
||||
│ │
|
||||
│ ─────────── Statistics ─────────── │
|
||||
│ │
|
||||
│ Calculate: Bytes/s, bits/s │
|
||||
│ Expected: 600-767 Kbps │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ Throughput │ │ Throughput │
|
||||
│ Client │ │ Server │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -95,8 +95,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
@@ -412,7 +412,7 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
phy_1m_conn_params.interval_min = 32;
|
||||
#endif
|
||||
phy_1m_conn_params.latency = 0;
|
||||
phy_1m_conn_params.supervision_timeout = 600;
|
||||
phy_1m_conn_params.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000);
|
||||
|
||||
esp_ble_gatt_creat_conn_params_t creat_conn_params = {0};
|
||||
memcpy(&creat_conn_params.remote_bda, scan_result->scan_rst.bda, ESP_BD_ADDR_LEN);
|
||||
|
||||
@@ -6,6 +6,48 @@
|
||||
This is the demo used to test the BLE throughput, this demo should used with throughput client demo together.
|
||||
The throughput of BLE can up to 720-767 Kbps between to ESP32 board.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Throughput Server│ │ Throughput Client│
|
||||
│ (this example) │ │ │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ 1. Initialize BLE │
|
||||
│ 2. Create GATT Service │
|
||||
│ 3. Add Characteristic (Notify) │
|
||||
│ 4. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Connection Setup ─────────── │
|
||||
│ │
|
||||
│ Connection Request │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ │
|
||||
│ 5. Accept Connection │
|
||||
│ │
|
||||
│ MTU Exchange (517 bytes) │
|
||||
│ <═══════════════════════════════════════════>│
|
||||
│ │
|
||||
│ Enable Notification │
|
||||
│ <════════════════════════════════════════════│
|
||||
│ │
|
||||
│ ─────────── Throughput Test ─────────── │
|
||||
│ │
|
||||
│ Notification Data (large packets) │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ Notification Data (large packets) │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ ... (continuous data stream) ... │
|
||||
│ ════════════════════════════════════════════>│
|
||||
│ │ Calculate
|
||||
│ │ Throughput
|
||||
│ │
|
||||
┌────────┴─────────┐ ┌────────┴─────────┐
|
||||
│ Throughput Server│ │ Throughput Client│
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -127,8 +127,8 @@ static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x000C, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(15), //slave connection max interval
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -143,8 +143,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
.set_scan_rsp = true,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006,
|
||||
.max_interval = 0x000C,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(15),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -158,8 +158,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
#endif /* CONFIG_EXAMPLE_SET_RAW_ADV_DATA */
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
//.peer_addr =
|
||||
|
||||
@@ -5,6 +5,65 @@
|
||||
|
||||
This example shows how to use ESP APIs to create a GATT Client.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ GATT Client │ │ GATT Server │
|
||||
│ (this example)│ │(gatt_server) │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Scanning Phase ─────────── │
|
||||
│ │
|
||||
│ 1. Start Scan │ Advertising
|
||||
│ ───────────────────────────────────────────────> │ "ESP_GATTS_DEMO"
|
||||
│ │
|
||||
│ 2. Found "ESP_GATTS_DEMO" │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Connection Phase ─────────── │
|
||||
│ │
|
||||
│ 3. Connect │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 4. Connection Established │
|
||||
│ <─────────────────────────────────────────────────│
|
||||
│ │
|
||||
│ 5. MTU Exchange │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ ─────────── Service Discovery ─────────── │
|
||||
│ │
|
||||
│ 6. Discover Service (UUID: 0x00FF) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 7. Service Found │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ 8. Get Characteristic (UUID: 0xFF01) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Enable Notification ─────────── │
|
||||
│ │
|
||||
│ 9. Register for Notify │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 10. Write CCCD (Enable Notify) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Data Exchange ─────────── │
|
||||
│ │
|
||||
│ 11. Write Characteristic │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 12. Receive Notification │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ GATT Client │ │ GATT Server │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -72,8 +72,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,59 @@
|
||||
|
||||
This example shows how to use the ESP BLE security APIs to secure connect to and encrypt with peer devices.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Security │ │ Security │
|
||||
│ Client │ │ Server │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Security Parameters Setup ───────── │
|
||||
│ │
|
||||
│ 1. Set IO Capability │
|
||||
│ 2. Set Auth Mode (Bonding, MITM, SC) │
|
||||
│ 3. Set Key Distribution │
|
||||
│ │
|
||||
│ ─────────── Connection Phase ─────────── │
|
||||
│ │
|
||||
│ 4. Scan for Server │ Advertising
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 5. Connect │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Connection Established │
|
||||
│ <─────────────────────────────────────────────────│
|
||||
│ │
|
||||
│ ─────────── Pairing & Encryption ─────────── │
|
||||
│ │
|
||||
│ 6. Start Encryption (esp_ble_set_encryption) │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ 7. Exchange Pairing Features │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ 8. Generate Keys (LTK, IRK, CSRK) │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ 9. Encrypt Link │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ 10. ESP_GAP_BLE_AUTH_CMPL_EVT │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Secure Data Exchange ─────────── │
|
||||
│ │
|
||||
│ Encrypted GATT Operations │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ Security │ │ Security │
|
||||
│ Client │ │ Server │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+2
-2
@@ -57,8 +57,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,56 @@ To test this example, you can run [gatt_security_client_demo](../gatt_security_c
|
||||
|
||||
Please, check this [tutorial](tutorial/Gatt_Security_Server_Example_Walkthrough.md) for more information about this example.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Security │ │ Security │
|
||||
│ Server │ │ Client │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Initialization ─────────── │
|
||||
│ │
|
||||
│ 1. Set Security Parameters │
|
||||
│ - IO Capability │
|
||||
│ - Auth Requirements │
|
||||
│ - Key Size │
|
||||
│ 2. Create GATT Service │
|
||||
│ 3. Start Advertising │
|
||||
│ │
|
||||
│ ─────────── Connection ─────────── │
|
||||
│ │
|
||||
│ Scan & Connect │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Security Request ─────────── │
|
||||
│ │
|
||||
│ ESP_GAP_BLE_SEC_REQ_EVT │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Send Security Response │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Pairing Process ─────────── │
|
||||
│ │
|
||||
│ Exchange Pairing Features │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ Key Generation & Distribution │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ Link Encrypted │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ ESP_GAP_BLE_AUTH_CMPL_EVT │
|
||||
│ ───────────────────────────────────────────────> │
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ Security │ │ Security │
|
||||
│ Server │ │ Client │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -49,8 +49,8 @@ static uint8_t sec_service_uuid[16] = {
|
||||
static esp_ble_adv_data_t heart_rate_adv_config = {
|
||||
.set_scan_rsp = false,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), //slave connection max interval
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -69,8 +69,8 @@ static esp_ble_adv_data_t heart_rate_scan_rsp_config = {
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t heart_rate_adv_params = {
|
||||
.adv_int_min = 0x100,
|
||||
.adv_int_max = 0x100,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(160),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(160),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -13,6 +13,62 @@ To test this demo, we can run the [gatt_client_demo](../gatt_client), which can
|
||||
|
||||
Please, check this [tutorial](tutorial/Gatt_Server_Example_Walkthrough.md) for more information about this example.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ GATT Server │ │ GATT Client │
|
||||
│(this example)│ │(gatt_client) │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ ─────────── Initialization ─────────── │
|
||||
│ │
|
||||
│ 1. Register GATT Server App │
|
||||
│ 2. Create Service (UUID: 0x00FF) │
|
||||
│ 3. Add Characteristic (UUID: 0xFF01) │
|
||||
│ 4. Add Descriptor (CCCD) │
|
||||
│ 5. Start Service │
|
||||
│ 6. Start Advertising "ESP_GATTS_DEMO" │
|
||||
│ │
|
||||
│ ─────────── Connection Phase ─────────── │
|
||||
│ │
|
||||
│ Scan & Connect │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Connection Established │
|
||||
│ ─────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ MTU Exchange │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ ─────────── Service Discovery ─────────── │
|
||||
│ │
|
||||
│ Service Discovery │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Return Service Info │
|
||||
│ ─────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ ─────────── Enable Notification ─────────── │
|
||||
│ │
|
||||
│ Write CCCD (0x0001) │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Notification Enabled │
|
||||
│ │
|
||||
│ ─────────── Data Exchange ─────────── │
|
||||
│ │
|
||||
│ Write Request │
|
||||
│ <─────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Send Notification │
|
||||
│ ─────────────────────────────────────────────────>│
|
||||
│ │
|
||||
┌──────┴───────┐ ┌──────┴───────┐
|
||||
│ GATT Server │ │ GATT Client │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
@@ -118,8 +118,8 @@ static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = false,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), //slave connection max interval
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -149,8 +149,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
#endif /* CONFIG_SET_RAW_ADV_DATA */
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
//.peer_addr =
|
||||
|
||||
@@ -7,6 +7,56 @@ This example shows how to create a GATT service with an attribute table defined
|
||||
|
||||
Please, check this [tutorial](tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md) for more information about this example.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ GATT Server Initialization Flow │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌───────────────────┐
|
||||
│ GATT Server │
|
||||
└─────────┬─────────┘
|
||||
│
|
||||
│ 1. Define Attribute Table (gatt_db[])
|
||||
│ ┌─────────────────────────────────────┐
|
||||
│ │ [0] Service Declaration │
|
||||
│ │ [1] Char Declaration │
|
||||
│ │ [2] Char Value │
|
||||
│ │ [3] CCCD (Notify Enable) │
|
||||
│ │ ... │
|
||||
│ └─────────────────────────────────────┘
|
||||
│
|
||||
│ 2. esp_ble_gatts_create_attr_tab()
|
||||
│ - Create all attributes at once
|
||||
│
|
||||
│ 3. ESP_GATTS_CREAT_ATTR_TAB_EVT
|
||||
│ - Receive handle table
|
||||
│
|
||||
│ 4. esp_ble_gatts_start_service()
|
||||
│
|
||||
│ 5. Start Advertising
|
||||
│
|
||||
▼
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ GATT Server │ │ GATT Client │
|
||||
│ (Advertising) │ │ │
|
||||
└─────────┬─────────┘ └─────────┬─────────┘
|
||||
│ │
|
||||
│ Scan & Connect │
|
||||
│ <───────────────────────────────────────────│
|
||||
│ │
|
||||
│ Service Discovery │
|
||||
│ ───────────────────────────────────────────>│
|
||||
│ │
|
||||
│ Read/Write/Notify Operations │
|
||||
│ <──────────────────────────────────────────>│
|
||||
│ │
|
||||
┌─────────┴─────────┐ ┌─────────┴─────────┐
|
||||
│ GATT Server │ │ GATT Client │
|
||||
└───────────────────┘ └───────────────────┘
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -94,8 +94,8 @@ static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5), //slave connection min interval
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20), //slave connection max interval
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //test_manufacturer,
|
||||
@@ -111,8 +111,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
.set_scan_rsp = true,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006,
|
||||
.max_interval = 0x0010,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
|
||||
.p_manufacturer_data = NULL, //&test_manufacturer[0],
|
||||
@@ -125,8 +125,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
#endif /* CONFIG_SET_RAW_ADV_DATA */
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -3,34 +3,169 @@
|
||||
|
||||
# ESP-IDF Gatt Client Multi Connection Example
|
||||
|
||||
This example shows the usage of APIs to create a GATT multi-connection client. It can be used to connect to three GATT servers at the same time.
|
||||
This example demonstrates how to use the BLE GATT client APIs to create a multi-connection client that can connect to multiple GATT servers simultaneously. By default, it supports connecting to up to 3 GATT servers at the same time.
|
||||
|
||||
To test this example, please run [gatt_server_demo](../gatt_server) to create three GATT server devices, namely ESP_GATTS_DEMO_a, ESP_GATTS_DEMO_b and ESP_GATTS_DEMO_c, `Gatt_client_multi_connection_demo` will connect to these three gatt server demos, and then exchange data.
|
||||
## How It Works
|
||||
|
||||
Please, check this [tutorial](tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md) for more information about this example.
|
||||
The example creates three GATT client profiles (A, B, C), each corresponding to one connection. It scans for devices with specific names, connects to them, discovers services, registers for notifications, and exchanges data with each server.
|
||||
|
||||
### Target Devices
|
||||
|
||||
The example searches for three GATT servers with the following names:
|
||||
- `ESP_GATTS_DEMO_a` → Profile A
|
||||
- `ESP_GATTS_DEMO_b` → Profile B
|
||||
- `ESP_GATTS_DEMO_c` → Profile C
|
||||
|
||||
You can use the [gatt_server](../gatt_server) example to create these server devices by modifying the device name.
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ GATT Client Multi-Connection │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────────────┐
|
||||
│ GATTC Client │
|
||||
│ (Multi-Connect) │
|
||||
└────────┬─────────┘
|
||||
│
|
||||
│ 1. Start Scanning
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ Scan for BLE Devices │
|
||||
│ Looking for: ESP_GATTS_DEMO_a, _b, _c │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Found device matching name?
|
||||
│
|
||||
├─────────────────────┬─────────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
|
||||
│ ESP_GATTS_DEMO_a│ │ ESP_GATTS_DEMO_b│ │ ESP_GATTS_DEMO_c│
|
||||
│ (Server A) │ │ (Server B) │ │ (Server C) │
|
||||
└───────┬────────┘ └───────┬────────┘ └───────┬────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ For Each Connected Device: │
|
||||
├───────────────────────────────────────────────────────────────────────┤
|
||||
│ 2. Stop Scanning │
|
||||
│ 3. Connect (esp_ble_gattc_enh_open) │
|
||||
│ 4. MTU Exchange │
|
||||
│ 5. Service Discovery (UUID: 0x00FF) │
|
||||
│ 6. Find Characteristic (UUID: 0xFF01) │
|
||||
│ 7. Register for Notification │
|
||||
│ 8. Write CCCD (Enable Notification) │
|
||||
│ 9. Write Test Data (35 bytes) │
|
||||
│ 10. Resume Scanning for remaining devices │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ All 3 devices connected?
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ Stop Scanning │
|
||||
│ Continue receiving notifications from all devices │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
┌────────────────────────────────────┐
|
||||
│ Connection Sequence Detail │
|
||||
└────────────────────────────────────┘
|
||||
|
||||
Client Server
|
||||
│ │
|
||||
│ ─────────── Connection Phase ─────────── │
|
||||
│ │
|
||||
│ Connect Request │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Connection Established │
|
||||
│ <────────────────────────────────────────────────>│
|
||||
│ │
|
||||
│ MTU Exchange Request │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ MTU Exchange Response │
|
||||
│ <──────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Service Discovery ─────────── │
|
||||
│ │
|
||||
│ Discover Services (UUID: 0x00FF) │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Service Found │
|
||||
│ <──────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ Get Characteristic (UUID: 0xFF01) │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Characteristic Found │
|
||||
│ <──────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ ─────────── Enable Notification ─────────── │
|
||||
│ │
|
||||
│ Register for Notify │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Write CCCD (0x0001 = Enable Notify) │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ ─────────── Data Exchange ─────────── │
|
||||
│ │
|
||||
│ Write Characteristic (35 bytes test data) │
|
||||
│ ────────────────────────────────────────────────> │
|
||||
│ │
|
||||
│ Notification (data from server) │
|
||||
│ <──────────────────────────────────────────────── │
|
||||
│ │
|
||||
```
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
### Hardware Required
|
||||
|
||||
* Four development boards with supported SoC:
|
||||
- One board for the GATT Client (this example)
|
||||
- Three boards for GATT Servers (using [gatt_server](../gatt_server) example)
|
||||
* Four USB cables for power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information.
|
||||
|
||||
### Setup GATT Servers
|
||||
|
||||
1. Flash the [gatt_server](../gatt_server) example to three separate boards
|
||||
2. Modify each server's device name before flashing:
|
||||
- Server 1: Change `ESP_GATT_DEMO` to `ESP_GATTS_DEMO_a`
|
||||
- Server 2: Change `ESP_GATT_DEMO` to `ESP_GATTS_DEMO_b`
|
||||
- Server 3: Change `ESP_GATT_DEMO` to `ESP_GATTS_DEMO_c`
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Set the correct chip target:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
The code can be modified to connect to more devices (up to 4 devices by default). If you need to connect to more devices (more than 4 devices), you need to change `BT/BLE MAX ACL CONNECTIONS` in menuconfig.
|
||||
**Connecting More Than 4 Devices:**
|
||||
|
||||
### Hardware Required
|
||||
The default maximum number of ACL connections is 4. To connect more devices:
|
||||
|
||||
* A development board with ESP32/ESP32-C3/ESP32-C2/ESP32-H2/ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
|
||||
Navigate to: `Component config` → `Bluetooth` → `Bluedroid Options` → `BT/BLE MAX ACL CONNECTIONS`
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
```bash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
|
||||
@@ -92,8 +92,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -66,32 +66,32 @@ static esp_ble_ext_scan_params_t ext_scan_params = {
|
||||
};
|
||||
|
||||
const esp_ble_conn_params_t phy_1m_conn_params = {
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.interval_min = 320,
|
||||
.interval_max = 320,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = 0,
|
||||
.max_ce_len = 0,
|
||||
};
|
||||
const esp_ble_conn_params_t phy_2m_conn_params = {
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.interval_min = 320,
|
||||
.interval_max = 320,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = 0,
|
||||
.max_ce_len = 0,
|
||||
};
|
||||
const esp_ble_conn_params_t phy_coded_conn_params = {
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.interval_min = 320, // 306-> 362Kbps
|
||||
.interval_max = 320,
|
||||
.latency = 0,
|
||||
.supervision_timeout = 600,
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
.min_ce_len = 0,
|
||||
.max_ce_len = 0,
|
||||
};
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -41,9 +41,9 @@
|
||||
static uint16_t profile_handle_table[HRS_IDX_NB];
|
||||
|
||||
static uint8_t ext_adv_raw_data[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd,
|
||||
0x11, 0X09, 'E', 'S', 'P', '_', 'B', 'L', 'E', '5', '0', '_', 'S', 'E', 'R', 'V', 'E', 'R',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb, 0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xab, 0xcd,
|
||||
0x11, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'B', 'L', 'E', '5', '0', '_', 'S', 'E', 'R', 'V', 'E', 'R',
|
||||
};
|
||||
|
||||
static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
@@ -52,8 +52,8 @@ static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
|
||||
.interval_min = 0x20,
|
||||
.interval_max = 0x20,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -110,9 +110,9 @@ const esp_ble_conn_params_t phy_1m_conn_params = {
|
||||
.latency = 0,
|
||||
.max_ce_len = 0,
|
||||
.min_ce_len = 0,
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.supervision_timeout = 600,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
};
|
||||
|
||||
const esp_ble_conn_params_t phy_2m_conn_params = {
|
||||
@@ -121,9 +121,9 @@ const esp_ble_conn_params_t phy_2m_conn_params = {
|
||||
.latency = 0,
|
||||
.max_ce_len = 0,
|
||||
.min_ce_len = 0,
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.supervision_timeout = 600,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
};
|
||||
|
||||
const esp_ble_conn_params_t phy_coded_conn_params = {
|
||||
@@ -132,9 +132,9 @@ const esp_ble_conn_params_t phy_coded_conn_params = {
|
||||
.latency = 0,
|
||||
.max_ce_len = 0,
|
||||
.min_ce_len = 0,
|
||||
.scan_interval = 0x40,
|
||||
.scan_window = 0x40,
|
||||
.supervision_timeout = 600,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(40),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(40),
|
||||
.supervision_timeout = ESP_BLE_GAP_SUPERVISION_TIMEOUT_MS(6000),
|
||||
};
|
||||
|
||||
struct gattc_profile_inst {
|
||||
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -98,12 +98,12 @@ static esp_attr_value_t gatts_demo_char1_val =
|
||||
};
|
||||
|
||||
static uint8_t ext_adv_raw_data[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x11, 0x07, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00,
|
||||
0x11, 0x07, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x14, 0X09, 'T', 'H', 'R', 'O', 'U', 'G', 'H', 'P', 'U', 'T', '_', 'P', 'H', 'Y', '_', 'D', 'E', 'M', 'O',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xab, 0xcd,
|
||||
0x11, ESP_BLE_AD_TYPE_128SRV_CMPL, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00,
|
||||
0x11, ESP_BLE_AD_TYPE_128SRV_CMPL, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x14, ESP_BLE_AD_TYPE_NAME_CMPL, 'T', 'H', 'R', 'O', 'U', 'G', 'H', 'P', 'U', 'T', '_', 'P', 'H', 'Y', '_', 'D', 'E', 'M', 'O',
|
||||
};
|
||||
|
||||
static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
@@ -112,8 +112,8 @@ static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
|
||||
.interval_min = 0x20,
|
||||
.interval_max = 0x20,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -49,8 +49,8 @@ static SemaphoreHandle_t test_sem = NULL;
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params_1M = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
|
||||
.interval_min = 0x30,
|
||||
.interval_max = 0x30,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(30),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(30),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -64,8 +64,8 @@ esp_ble_gap_ext_adv_params_t ext_adv_params_1M = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE,
|
||||
.interval_min = 0x40,
|
||||
.interval_max = 0x40,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -79,8 +79,8 @@ esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t legacy_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND,
|
||||
.interval_min = 0x45,
|
||||
.interval_max = 0x45,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(43),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(43),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -94,8 +94,8 @@ esp_ble_gap_ext_adv_params_t legacy_adv_params = {
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params_coded = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE,
|
||||
.interval_min = 0x50,
|
||||
.interval_max = 0x50,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(50),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(50),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -108,37 +108,37 @@ esp_ble_gap_ext_adv_params_t ext_adv_params_coded = {
|
||||
};
|
||||
|
||||
static uint8_t raw_adv_data_1m[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x11, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x11, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
'D', 'V', '_', '1', 'M'
|
||||
};
|
||||
|
||||
static uint8_t raw_scan_rsp_data_2m[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x11, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x11, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
'D', 'V', '_', '2', 'M'
|
||||
};
|
||||
|
||||
static uint8_t legacy_adv_data[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x14, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x14, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
'D', 'V', '_', 'C', 'O', 'D', 'E', 'D'
|
||||
};
|
||||
|
||||
static uint8_t legacy_scan_rsp_data[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x15, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x15, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
'D', 'V', '_', 'L', 'E', 'G', 'A', 'C', 'Y'
|
||||
};
|
||||
|
||||
static uint8_t raw_scan_rsp_data_coded[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb,
|
||||
0x14, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
|
||||
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
|
||||
0x14, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
|
||||
'D', 'V', '_', 'C', 'O', 'D', 'E', 'D'
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -58,8 +58,8 @@ static SemaphoreHandle_t test_sem = NULL;
|
||||
|
||||
esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED,
|
||||
.interval_min = 0x30,
|
||||
.interval_max = 0x30,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(30),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(30),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
@@ -72,8 +72,8 @@ esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
};
|
||||
|
||||
static esp_ble_gap_periodic_adv_params_t periodic_adv_params = {
|
||||
.interval_min = 0x40, // 80 ms interval
|
||||
.interval_max = 0x40,
|
||||
.interval_min = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(80),
|
||||
.interval_max = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(80),
|
||||
.properties = 0, // Do not include TX power
|
||||
};
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ esp_attr_value_t gatts_initial_char_val = {
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x060,
|
||||
.adv_int_max = 0x060,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(60),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(60),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -145,8 +145,8 @@ static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x20,
|
||||
.max_interval = 0x40,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(40),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(80),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
@@ -162,8 +162,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
.set_scan_rsp = true,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006,
|
||||
.max_interval = 0x0010,
|
||||
.min_interval = ESP_BLE_GAP_CONN_ITVL_MS(7.5),
|
||||
.max_interval = ESP_BLE_GAP_CONN_ITVL_MS(20),
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
@@ -176,8 +176,8 @@ static esp_ble_adv_data_t scan_rsp_data = {
|
||||
#endif /* CONFIG_SET_RAW_ADV_DATA */
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_int_min = ESP_BLE_GAP_ADV_ITVL_MS(20),
|
||||
.adv_int_max = ESP_BLE_GAP_ADV_ITVL_MS(40),
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
@@ -215,8 +215,8 @@ static esp_ble_scan_params_t ble_scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_interval = ESP_BLE_GAP_SCAN_ITVL_MS(50),
|
||||
.scan_window = ESP_BLE_GAP_SCAN_WIN_MS(30),
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* BLE Combined Advertising and Scanning Example.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
static const char *TAG = "BLE_ADV_SCAN";
|
||||
|
||||
#define SCAN_LOCAL_NAME_MAX_LEN 32
|
||||
|
||||
typedef struct {
|
||||
char scan_local_name[32];
|
||||
char scan_local_name[SCAN_LOCAL_NAME_MAX_LEN];
|
||||
uint8_t name_len;
|
||||
} ble_scan_local_name_t;
|
||||
|
||||
@@ -187,28 +189,58 @@ static void hci_cmd_send_ble_set_adv_data(void)
|
||||
ESP_LOGI(TAG, "Starting BLE advertising with name \"%s\"", adv_name);
|
||||
}
|
||||
|
||||
static esp_err_t get_local_name (uint8_t *data_msg, uint8_t data_len, ble_scan_local_name_t *scanned_packet)
|
||||
static esp_err_t get_local_name(uint8_t *data_msg, uint8_t data_len, ble_scan_local_name_t *scanned_packet)
|
||||
{
|
||||
uint8_t curr_ptr = 0, curr_len, curr_type;
|
||||
uint8_t curr_ptr = 0;
|
||||
|
||||
/* Initialize output structure */
|
||||
scanned_packet->name_len = 0;
|
||||
scanned_packet->scan_local_name[0] = '\0';
|
||||
|
||||
while (curr_ptr < data_len) {
|
||||
curr_len = data_msg[curr_ptr++];
|
||||
curr_type = data_msg[curr_ptr++];
|
||||
/* Ensure there is at least 1 byte for length field */
|
||||
if (curr_ptr >= data_len) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t curr_len = data_msg[curr_ptr++];
|
||||
|
||||
/* Length of 0 indicates end of AD structures or invalid data */
|
||||
if (curr_len == 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Search for current data type and see if it contains name as data (0x08 or 0x09). */
|
||||
if (curr_type == 0x08 || curr_type == 0x09) {
|
||||
for (uint8_t i = 0; i < curr_len - 1; i += 1) {
|
||||
scanned_packet->scan_local_name[i] = data_msg[curr_ptr + i];
|
||||
}
|
||||
scanned_packet->name_len = curr_len - 1;
|
||||
return ESP_OK;
|
||||
} else {
|
||||
/* Search for next data. Current length includes 1 octate for AD Type (2nd octate). */
|
||||
curr_ptr += curr_len - 1;
|
||||
/* Ensure there is at least 1 byte for type field */
|
||||
if (curr_ptr >= data_len) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t curr_type = data_msg[curr_ptr++];
|
||||
|
||||
/* Calculate data field length (curr_len includes type byte) */
|
||||
uint8_t data_field_len = curr_len - 1;
|
||||
|
||||
/* Verify remaining buffer has enough data */
|
||||
if (curr_ptr + data_field_len > data_len) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Check for Local Name type (0x08: Shortened, 0x09: Complete) */
|
||||
if (curr_type == 0x08 || curr_type == 0x09) {
|
||||
/* Limit copy length to prevent buffer overflow */
|
||||
uint8_t copy_len = data_field_len;
|
||||
if (copy_len > SCAN_LOCAL_NAME_MAX_LEN - 1) {
|
||||
copy_len = SCAN_LOCAL_NAME_MAX_LEN - 1;
|
||||
}
|
||||
|
||||
memcpy(scanned_packet->scan_local_name, &data_msg[curr_ptr], copy_len);
|
||||
scanned_packet->scan_local_name[copy_len] = '\0'; /* Ensure null termination */
|
||||
scanned_packet->name_len = copy_len;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Move to next AD structure */
|
||||
curr_ptr += data_field_len;
|
||||
}
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user