feat(bt/bluedroid): Added BLE 5.0 throughput examples

(cherry picked from commit 6d3a82eecfc0d86d699ccb7cc499f27863ab5616)

Co-authored-by: zhangbowen <zhangbowen@espressif.com>
This commit is contained in:
Chen Jian Hua 2024-11-19 10:33:33 +08:00 committed by chenjianhua
parent aa07a85df2
commit 28e1524c7e
18 changed files with 1609 additions and 0 deletions

View File

@ -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(throughput_client_demo)

View File

@ -0,0 +1,121 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- |
# ESP-IDF BLE 50 throughput GATT CLIENT Test
This is the demo used to test the BLE 5.0 throughput, this demo should used with throughput server demo together.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
To configure the project, you can follow these steps:
1. We can only test notify or write throughput at the same time, this demo default to test the notify throughput, if want to test the write throughput,
please set: `idf.py menuconfig --> Component config --> Example 'GATT CLIENT THROUGHPUT' Config --->` then select the `test the gattc write throughput` option.
2. This demo only test unidirectional throughput, if you want to test the bidirectional throughput please change the demo by yourself.
3. Should change the CPU frequency to 160 MHZ in the `idf.py menuconfig` and `Component config ---> ESP System Settings ---> CPU frequency (160 MHz)`.
4. In order to maximize throughput, please test in a clean environment without many BLE devices working and esure both test devices are ESP32 series.
### Hardware Required
* A development board with supported SoC (e.g., ESP32-C3-DevKitM-1, ESP32-C6-DevKitC-1, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(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
### Throughput on 1M PHY
```
I (458) GATTC_DEMO_PHY: Legacy adv, adv type 0x13 data len 31
I (458) GATTC_DEMO_PHY: Extend adv, adv type 0x1 data len 67
I (458) GATTC_DEMO_PHY: searched device THROUGHPUT_PHY_DEMO
I (458) GATTC_DEMO_PHY: Device found ec:da:3b:0f:2d:b6
I (468) Adv name: THROUGHPUT_PHY_D
I (468) Adv name: EMO
I (468) GATTC_DEMO_PHY: Stop extend scan and create aux open, primary_phy 1 secondary phy 1
I (488) GATTC_DEMO_PHY: Scanning stop successfully
I (768) GATTC_DEMO_PHY: Connected, conn_id 0, remote ec:da:3b:0f:2d:b6
I (768) GATTC_DEMO_PHY: Open successfully, MTU 23
I (778) GATTC_DEMO_PHY: Read PHY, status 0, TX_PHY 1, RX_PHY 1
I (4928) GATTC_DEMO_PHY: MTU exchange, status 0, MTU 517
I (4928) GATTC_DEMO_PHY: Service search result
I (4928) GATTC_DEMO_PHY: Service found
I (4928) GATTC_DEMO_PHY: UUID16: ff
I (4938) GATTC_DEMO_PHY: Service search complete
I (4938) GATTC_DEMO_PHY: Notification register successfully
I (5448) GATTC_DEMO_PHY: Descriptor write successfully
I (6438) GATTC_DEMO_PHY: Notify Bit rate = 97642 Byte/s, = 781136 bit/s, time = 0s
I (8438) GATTC_DEMO_PHY: Notify Bit rate = 97390 Byte/s, = 779120 bit/s, time = 2s
I (10438) GATTC_DEMO_PHY: Notify Bit rate = 97233 Byte/s, = 777864 bit/s, time = 4s
I (12438) GATTC_DEMO_PHY: Notify Bit rate = 97178 Byte/s, = 777424 bit/s, time = 6s
I (14438) GATTC_DEMO_PHY: Notify Bit rate = 97142 Byte/s, = 777136 bit/s, time = 8s
```
### Throughput on 2M PHY
```
I (648) GATTC_DEMO_PHY: Read PHY, status 0, TX_PHY 2, RX_PHY 2
I (4798) GATTC_DEMO_PHY: MTU exchange, status 0, MTU 517
I (4798) GATTC_DEMO_PHY: Service search result
I (4798) GATTC_DEMO_PHY: Service found
I (4798) GATTC_DEMO_PHY: UUID16: ff
I (4808) GATTC_DEMO_PHY: Service search complete
I (4808) GATTC_DEMO_PHY: Notification register successfully
I (5318) GATTC_DEMO_PHY: Descriptor write successfully
I (6448) GATTC_DEMO_PHY: Notify Bit rate = 175369 Byte/s, = 1402952 bit/s, time = 1s
I (8448) GATTC_DEMO_PHY: Notify Bit rate = 175270 Byte/s, = 1402160 bit/s, time = 3s
I (10448) GATTC_DEMO_PHY: Notify Bit rate = 175251 Byte/s, = 1402008 bit/s, time = 5s
I (12448) GATTC_DEMO_PHY: Notify Bit rate = 175242 Byte/s, = 1401936 bit/s, time = 7s
I (14448) GATTC_DEMO_PHY: Notify Bit rate = 175192 Byte/s, = 1401536 bit/s, time = 9s
```
### Throughput on 500K PHY (Coded S2)
```
I (908) GATTC_DEMO_PHY: Read PHY, status 0, TX_PHY 3, RX_PHY 3
I (5058) GATTC_DEMO_PHY: MTU exchange, status 0, MTU 517
I (5058) GATTC_DEMO_PHY: Service search result
I (5058) GATTC_DEMO_PHY: Service found
I (5068) GATTC_DEMO_PHY: UUID16: ff
I (5068) GATTC_DEMO_PHY: Service search complete
I (5068) GATTC_DEMO_PHY: Notification register successfully
I (5578) GATTC_DEMO_PHY: Descriptor write successfully
I (6468) GATTC_DEMO_PHY: Notify Bit rate = 44292 Byte/s, = 354336 bit/s, time = 0s
I (8468) GATTC_DEMO_PHY: Notify Bit rate = 43961 Byte/s, = 351688 bit/s, time = 2s
I (10468) GATTC_DEMO_PHY: Notify Bit rate = 43898 Byte/s, = 351184 bit/s, time = 4s
I (12468) GATTC_DEMO_PHY: Notify Bit rate = 43871 Byte/s, = 350968 bit/s, time = 6s
I (14468) GATTC_DEMO_PHY: Notify Bit rate = 43857 Byte/s, = 350856 bit/s, time = 8s
```
### Throughput on 125K PHY (Coded S8)
```
I (778) GATTC_DEMO_PHY: Read PHY, status 0, TX_PHY 3, RX_PHY 3
I (4928) GATTC_DEMO_PHY: MTU exchange, status 0, MTU 517
I (4938) GATTC_DEMO_PHY: Service search result
I (4938) GATTC_DEMO_PHY: Service found
I (4938) GATTC_DEMO_PHY: UUID16: ff
I (4938) GATTC_DEMO_PHY: Service search complete
I (4938) GATTC_DEMO_PHY: Notification register successfully
I (5448) GATTC_DEMO_PHY: Descriptor write successfully
I (6448) GATTC_DEMO_PHY: Notify Bit rate = 13459 Byte/s, = 107672 bit/s, time = 0s
I (8448) GATTC_DEMO_PHY: Notify Bit rate = 13395 Byte/s, = 107160 bit/s, time = 2s
I (10448) GATTC_DEMO_PHY: Notify Bit rate = 13383 Byte/s, = 107064 bit/s, time = 4s
I (12448) GATTC_DEMO_PHY: Notify Bit rate = 13378 Byte/s, = 107024 bit/s, time = 6s
I (14448) GATTC_DEMO_PHY: Notify Bit rate = 13375 Byte/s, = 107000 bit/s, time = 8s
```
## 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.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "example_ble_client_throughput.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,14 @@
menu "Example 'GATT CLIENT THROUGHPUT' Config"
config GATTS_NOTIFY_THROUGHPUT
bool "test the gatts notify throughput"
help
If this config item is set, then the 'GATTC_WRITE_THROUGHPUT' config should be close, it can't test both
write or notify at the same time at this demo
config GATTC_WRITE_THROUGHPUT
bool "test the gattc write throughput"
help
If this config item is set, then the 'GATTS_NOTIFY_THROUGHPUT' config should be close, it can't test both
write or notify at the same time at this demo
endmenu

View File

@ -0,0 +1,649 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/****************************************************************************
*
* This is the demo to test the BLE throughput. It should be used together with throughput_server demo.
*
****************************************************************************/
#include "sdkconfig.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <inttypes.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/semphr.h"
#include "freertos/task.h"
#include "esp_timer.h"
/**********************************************************
* Thread/Task reference
**********************************************************/
#ifdef CONFIG_BLUEDROID_PINNED_TO_CORE
#define BLUETOOTH_TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY)
#else
#define BLUETOOTH_TASK_PINNED_TO_CORE (0)
#endif
#define REMOTE_SERVICE_UUID 0x00FF
#define REMOTE_NOTIFY_CHAR_UUID 0xFF01
#define PROFILE_NUM 1
#define PROFILE_A_APP_ID 0
#define INVALID_HANDLE 0
#define SECOND_TO_USECOND 1000000
#define EXT_SCAN_DURATION 0
#define EXT_SCAN_PERIOD 0
static const char *GATTC_TAG = "GATTC_DEMO_PHY";
static const char remote_device_name[] = "THROUGHPUT_PHY_DEMO";
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;
#if (CONFIG_GATTS_NOTIFY_THROUGHPUT)
static bool start = false;
static uint64_t notify_len = 0;
static uint64_t start_time = 0;
static uint64_t current_time = 0;
#endif /* #if (CONFIG_GATTS_NOTIFY_THROUGHPUT) */
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
#define GATTC_WRITE_LEN 495
static bool can_send_write = false;
static SemaphoreHandle_t gattc_semaphore;
uint8_t write_data[GATTC_WRITE_LEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f};
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
static bool is_connect = false;
/* 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);
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_NOTIFY_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_ext_scan_params_t ext_scan_params = {
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
.filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE,
.cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_CODE_MASK | ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK,
.uncoded_cfg = {BLE_SCAN_TYPE_PASSIVE, 40, 40},
.coded_cfg = {BLE_SCAN_TYPE_PASSIVE, 40, 40},
};
// If the interference in the air is severe, the connection interval can be reduced.
const esp_ble_gap_conn_params_t phy_1m_conn_params = {
.interval_max = 104, // 130ms
.interval_min = 104,
.latency = 0,
.max_ce_len = 0,
.min_ce_len = 0,
.scan_interval = 0x40,
.scan_window = 0x40,
.supervision_timeout = 600,
};
const esp_ble_gap_conn_params_t phy_2m_conn_params = {
.interval_max = 104, // 130ms
.interval_min = 104,
.latency = 0,
.max_ce_len = 0,
.min_ce_len = 0,
.scan_interval = 0x40,
.scan_window = 0x40,
.supervision_timeout = 600,
};
const esp_ble_gap_conn_params_t phy_coded_conn_params = {
.interval_max = 104, // 130ms
.interval_min = 104,
.latency = 0,
.max_ce_len = 0,
.min_ce_len = 0,
.scan_interval = 0x40,
.scan_window = 0x40,
.supervision_timeout = 600,
};
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;
};
/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_A_APP_ID] = {
.gattc_cb = gattc_profile_event_handler,
.gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
},
};
static uint8_t check_sum(uint8_t *addr, uint16_t count)
{
uint32_t sum = 0;
if (addr == NULL || count == 0) {
return 0;
}
for(int i = 0; i < count; i++) {
sum = sum + addr[i];
}
while (sum >> 8) {
sum = (sum & 0xff) + (sum >> 8);
}
return (uint8_t)~sum;
}
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, "GATT client register, status %d, app_id %d, gattc_if %d", param->reg.status, param->reg.app_id, gattc_if);
esp_err_t scan_ret = esp_ble_gap_set_ext_scan_params(&ext_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, "Connected, conn_id %d, remote "ESP_BD_ADDR_STR"", p_data->connect.conn_id,
ESP_BD_ADDR_HEX(p_data->connect.remote_bda));
gl_profile_tab[PROFILE_A_APP_ID].conn_id = p_data->connect.conn_id;
memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
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);
}
esp_ble_gap_read_phy(p_data->connect.remote_bda);
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 successfully, MTU %u", param->open.mtu);
break;
case ESP_GATTC_CFG_MTU_EVT:
is_connect = true;
ESP_LOGI(GATTC_TAG, "MTU exchange, status %d, MTU %d", param->cfg_mtu.status, param->cfg_mtu.mtu);
esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid);
break;
case ESP_GATTC_SEARCH_RES_EVT: {
ESP_LOGI(GATTC_TAG, "Service search result");
esp_gatt_srvc_id_t *srvc_id =(esp_gatt_srvc_id_t *)&p_data->search_res.srvc_id;
if (srvc_id->id.uuid.len == ESP_UUID_LEN_16 && srvc_id->id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
ESP_LOGI(GATTC_TAG, "Service found");
get_server = true;
gl_profile_tab[PROFILE_A_APP_ID].service_start_handle = p_data->search_res.start_handle;
gl_profile_tab[PROFILE_A_APP_ID].service_end_handle = p_data->search_res.end_handle;
ESP_LOGI(GATTC_TAG, "UUID16: %x", srvc_id->id.uuid.uuid.uuid16);
}
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT:
if (p_data->search_cmpl.status != ESP_GATT_OK){
ESP_LOGE(GATTC_TAG, "Service search failed, status %x", p_data->search_cmpl.status);
break;
}
ESP_LOGI(GATTC_TAG, "Service search complete");
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_A_APP_ID].service_start_handle,
gl_profile_tab[PROFILE_A_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_A_APP_ID].service_start_handle,
gl_profile_tab[PROFILE_A_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;
}
/* Every service has only one char in our 'throughput_server' demo, so we use first 'char_elem_result' */
if (count > 0 && (char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)){
gl_profile_tab[PROFILE_A_APP_ID].char_handle = char_elem_result[0].char_handle;
esp_ble_gattc_register_for_notify (gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, char_elem_result[0].char_handle);
}
}
/* free char_elem_result */
free(char_elem_result);
char_elem_result = NULL;
}else{
ESP_LOGE(GATTC_TAG, "no char found");
}
}
break;
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
if (p_data->reg_for_notify.status != ESP_GATT_OK){
ESP_LOGE(GATTC_TAG, "Notification register failed, status %d", p_data->reg_for_notify.status);
}else{
ESP_LOGI(GATTC_TAG, "Notification register successfully");
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_A_APP_ID].conn_id,
ESP_GATT_DB_DESCRIPTOR,
gl_profile_tab[PROFILE_A_APP_ID].service_start_handle,
gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,
gl_profile_tab[PROFILE_A_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_A_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");
}
/* Every char has only one descriptor in our 'throughput_server' demo, so we use first 'descr_elem_result' */
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_A_APP_ID].conn_id,
descr_elem_result[0].handle,
sizeof(notify_en),
(uint8_t *)&notify_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 */
free(descr_elem_result);
}
}
else{
ESP_LOGE(GATTC_TAG, "decsr not found");
}
}
break;
}
case ESP_GATTC_NOTIFY_EVT: {
#if (CONFIG_GATTS_NOTIFY_THROUGHPUT)
if (p_data->notify.is_notify &&
(p_data->notify.value[p_data->notify.value_len - 1] ==
check_sum(p_data->notify.value, p_data->notify.value_len - 1))){
notify_len += p_data->notify.value_len;
} else {
ESP_LOGE(GATTC_TAG, "Indication received, value:");
}
if (start == false) {
start_time = esp_timer_get_time();
start = true;
break;
}
#endif /* #if (CONFIG_GATTS_NOTIFY_THROUGHPUT) */
break;
}
case ESP_GATTC_WRITE_DESCR_EVT:
if (p_data->write.status != ESP_GATT_OK) {
ESP_LOGE(GATTC_TAG, "Descriptor write failed, status %x", p_data->write.status);
break;
}
ESP_LOGI(GATTC_TAG, "Descriptor write successfully");
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
can_send_write = true;
xSemaphoreGive(gattc_semaphore);
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
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, "Service change from "ESP_BD_ADDR_STR"", ESP_BD_ADDR_HEX(bda));
break;
}
case ESP_GATTC_WRITE_CHAR_EVT:
if (p_data->write.status != ESP_GATT_OK) {
ESP_LOGE(GATTC_TAG, "Characteristic write failed, status %x", p_data->write.status);
break;
}
break;
case ESP_GATTC_DISCONNECT_EVT:
is_connect = false;
get_server = false;
#if (CONFIG_GATTS_NOTIFY_THROUGHPUT)
start = false;
start_time = 0;
current_time = 0;
notify_len = 0;
#endif /* #if (CONFIG_GATTS_NOTIFY_THROUGHPUT) */
ESP_LOGI(GATTC_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
ESP_BD_ADDR_HEX(p_data->disconnect.remote_bda), p_data->disconnect.reason);
break;
case ESP_GATTC_CONGEST_EVT:
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
if (param->congest.congested) {
can_send_write = false;
} else {
can_send_write = true;
xSemaphoreGive(gattc_semaphore);
}
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
break;
default:
break;
}
}
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT: {
if (param->set_ext_scan_params.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG,"Extend scanning parameters set failed, status %x", param->set_ext_scan_params.status);
break;
}
esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION,EXT_SCAN_PERIOD);
break;
}
case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT:
//scan start complete event to indicate scan start successfully or failed
if (param->ext_scan_start.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG, "Extended scanning start failed, status %x", param->ext_scan_start.status);
break;
}
ESP_LOGI(GATTC_TAG, "Extended scanning start successfully");
break;
case ESP_GAP_BLE_EXT_ADV_REPORT_EVT: {
uint8_t *adv_name = NULL;
uint8_t adv_name_len = 0;
if(param->ext_adv_report.params.event_type & ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
ESP_LOGI(GATTC_TAG, "Legacy adv, adv type 0x%x data len %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len);
} else {
ESP_LOGI(GATTC_TAG, "Extend adv, adv type 0x%x data len %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len);
}
adv_name = esp_ble_resolve_adv_data_by_type(param->ext_adv_report.params.adv_data,
param->ext_adv_report.params.adv_data_len,
ESP_BLE_AD_TYPE_NAME_CMPL,
&adv_name_len);
if (!connect && 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);
connect = true;
esp_ble_gap_stop_ext_scan();
ESP_LOGI(GATTC_TAG, "Device found "ESP_BD_ADDR_STR"", ESP_BD_ADDR_HEX(param->ext_adv_report.params.addr));
ESP_LOG_BUFFER_CHAR("Adv name", adv_name, adv_name_len);
ESP_LOGI(GATTC_TAG, "Stop extend scan and create aux open, primary_phy %d secondary phy %d", param->ext_adv_report.params.primary_phy, param->ext_adv_report.params.secondly_phy);
esp_ble_gap_prefer_ext_connect_params_set(param->ext_adv_report.params.addr,
ESP_BLE_GAP_PHY_1M_PREF_MASK | ESP_BLE_GAP_PHY_2M_PREF_MASK | ESP_BLE_GAP_PHY_CODED_PREF_MASK,
&phy_1m_conn_params, &phy_2m_conn_params, &phy_coded_conn_params);
esp_ble_gattc_aux_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if,
param->ext_adv_report.params.addr,
param->ext_adv_report.params.addr_type, true);
}
break;
}
case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT:
if (param->ext_scan_stop.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG, "Scanning stop failed, status %x", param->ext_scan_stop.status);
break;
}
ESP_LOGI(GATTC_TAG, "Scanning stop successfully");
break;
case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
if (param->ext_adv_stop.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG, "Advertising stop failed, status %x", param->ext_adv_stop.status);
break;
}
ESP_LOGI(GATTC_TAG, "Advertising stop successfully");
break;
case ESP_GAP_BLE_READ_PHY_COMPLETE_EVT:
ESP_LOGI(GATTC_TAG, "Read PHY, status %x, TX_PHY %u, RX_PHY %u", param->read_phy.status,
param->read_phy.tx_phy, param->read_phy.rx_phy);
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(GATTC_TAG, "Connection params update, 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 esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
/* If event is register event, store the gattc_if for each profile */
if (event == ESP_GATTC_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
gl_profile_tab[param->reg.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;
}
}
/* If the gattc_if equal to profile A, call profile A cb handler,
* so here call each profile's callback */
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
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);
}
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
static void throughput_client_task(void *param)
{
vTaskDelay(2000 / portTICK_PERIOD_MS);
uint8_t sum = check_sum(write_data, sizeof(write_data) - 1);
write_data[GATTC_WRITE_LEN - 1] = sum;
while(1) {
if (!can_send_write) {
int res = xSemaphoreTake(gattc_semaphore, portMAX_DELAY);
assert(res == pdTRUE);
} else {
if (is_connect) {
int free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);
if(free_buff_num > 0) {
for( ; free_buff_num > 0; free_buff_num--) {
// the app data set to 490 just for divided into two packages to send in the low layer
// when the packet length set to 251.
esp_ble_gattc_write_char(gl_profile_tab[PROFILE_A_APP_ID].gattc_if,
gl_profile_tab[PROFILE_A_APP_ID].conn_id,
gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(write_data), write_data,
ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
}
} else { //Add the vTaskDelay to prevent this task from consuming the CPU all the time, causing low-priority tasks to not be executed at all.
vTaskDelay( 10 / portTICK_PERIOD_MS );
}
} else {
vTaskDelay(300 / portTICK_PERIOD_MS );
}
}
}
}
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
#if (CONFIG_GATTS_NOTIFY_THROUGHPUT)
static void throughput_cal_task(void *param)
{
while (1)
{
vTaskDelay(2000 / portTICK_PERIOD_MS);
if(is_connect){
uint32_t bit_rate = 0;
if (start_time) {
current_time = esp_timer_get_time();
bit_rate = notify_len * SECOND_TO_USECOND / (current_time - start_time);
ESP_LOGI(GATTC_TAG, "Notify Bit rate = %" PRIu32 " Byte/s, = %" PRIu32 " bit/s, time = %ds",
bit_rate, bit_rate<<3, (int)((current_time - start_time) / SECOND_TO_USECOND));
} else {
ESP_LOGI(GATTC_TAG, "Notify Bit rate = 0 Byte/s, = 0 bit/s");
}
}
}
}
#endif /* #if (CONFIG_GATTS_NOTIFY_THROUGHPUT) */
void app_main(void)
{
// Initialize NVS.
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, error code = %x", __func__, ret);
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(GATTC_TAG, "%s enable controller failed, error code = %x", __func__, ret);
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTC_TAG, "%s init bluetooth failed, error code = %x", __func__, ret);
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed, error code = %x", __func__, ret);
return;
}
//register the callback function to the gap module
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;
}
//register the callback function to the gattc module
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_gattc_app_register(PROFILE_A_APP_ID);
if (ret){
ESP_LOGE(GATTC_TAG, "%s gattc app register failed, error code = %x", __func__, ret);
}
// set the maximum MTU for used.
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);
}
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
// The task is only created on the CPU core that Bluetooth is working on,
// preventing the sending task from using the un-updated Bluetooth state on another CPU.
xTaskCreatePinnedToCore(&throughput_client_task, "throughput_client_task", 4096, NULL, 10, NULL, BLUETOOTH_TASK_PINNED_TO_CORE);
#endif
#if (CONFIG_GATTS_NOTIFY_THROUGHPUT)
xTaskCreatePinnedToCore(&throughput_cal_task, "throughput_cal_task", 4096, NULL, 9, NULL, BLUETOOTH_TASK_PINNED_TO_CORE);
#endif
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
gattc_semaphore = xSemaphoreCreateBinary();
if (!gattc_semaphore) {
ESP_LOGE(GATTC_TAG, "%s, init fail, the gattc semaphore create fail.", __func__);
return;
}
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
}

View File

@ -0,0 +1,10 @@
# 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=y
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=n
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not used on ESP32, ESP32-C3 and ESP32-S3.
# CONFIG_BT_LE_50_FEATURE_SUPPORT=n
CONFIG_GATTS_NOTIFY_THROUGHPUT=y
CONFIG_GATTC_WRITE_THROUGHPUT=n

View File

@ -0,0 +1,8 @@
# 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_LE_50_FEATURE_SUPPORT=y
CONFIG_BT_LE_HCI_EVT_BUF_SIZE=257
CONFIG_XTAL_FREQ_26=y

View File

@ -0,0 +1,5 @@
# 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="esp32c3"
CONFIG_BT_ENABLED=y

View File

@ -0,0 +1,5 @@
# 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="esp32s3"
CONFIG_BT_ENABLED=y

View File

@ -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(throughput_server_demo)

View File

@ -0,0 +1,68 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- |
# ESP-IDF BLE 50 throughput GATT SERVER Test
This is the demo used to test the BLE throughput, this demo should used with throughput client demo together.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
To configure the project, you can follow these steps:
1. We can only test notify or write throughput at the same time, this demo default to test the notify throughput, if want to test the write throughput,
please set: `idf.py menuconfig --> Component config --> Example 'GATT SERVER THROUGHPUT' Config --->` then select the `test the gattc write throughput` option.
2. This demo only test unidirectional throughput, if you want to test the bidirectional throughput please change the demo by yourself.
3. Should change the CPU frequency to 160 MHZ in the `idf.py menuconfig` and `Component config ---> ESP System Settings ---> CPU frequency (160 MHz)`.
4. In order to maximize throughput, please test in a clean environment without many BLE devices working and esure both test devices are ESP32 series.
### Hardware Required
* A development board with supported SoC (e.g., ESP32-C3-DevKitM-1, ESP32-C6-DevKitC-1, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(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 (377) main_task: Started on CPU0
I (377) main_task: Calling app_main()
I (377) BLE_INIT: BT controller compile version [d752dea]
I (377) BLE_INIT: Bluetooth MAC: ec:da:3b:0f:2d:b6
I (377) phy_init: phy_version 1180,01f2a49,Jun 4 2024,16:34:25
I (437) GATTS_DEMO_PHY: GATT server register, status 0, app_id 0
I (437) GATTS_DEMO_PHY: Extended advertising params set, status 0
I (437) GATTS_DEMO_PHY: Service create, status 0, service_handle 40
I (447) GATTS_DEMO_PHY: Extended advertising data set, status 0
I (447) GATTS_DEMO_PHY: Service start, status 0, service_handle 40
I (457) GATTS_DEMO_PHY: Characteristic add, status 0, attr_handle 42, service_handle 40
I (467) GATTS_DEMO_PHY: the gatts demo char length = 3
I (467) GATTS_DEMO_PHY: prf_char[0] =11
I (477) GATTS_DEMO_PHY: prf_char[1] =22
I (477) GATTS_DEMO_PHY: prf_char[2] =33
I (477) GATTS_DEMO_PHY: Extended advertising start, status 0
I (487) GATTS_DEMO_PHY: Descriptor add, status 0, attr_handle 43, service_handle 40
I (497) main_task: Returned from app_main()
I (8957) GATTS_DEMO_PHY: Extended advertising terminated, status 0
I (8957) GATTS_DEMO_PHY: Advertising successfully ended with a connection being created
I (9087) GATTS_DEMO_PHY: Connected, conn_id 0, remote 68:67:25:4d:11:fa
I (13117) GATTS_DEMO_PHY: MTU exchange, MTU 517
I (13637) GATTS_DEMO_PHY: Notification enable
```
## 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.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "example_ble_server_throughput.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,37 @@
menu "Example 'GATT SERVER THROUGHPUT' Config"
config EXAMPLE_GATTS_NOTIFY_THROUGHPUT
bool "test the gatts notify throughput"
help
If this config item is set, then the 'EXAMPLE_GATTC_WRITE_THROUGHPUT' config should be close, it can't test
both write or notify at the same time at this demo
config EXAMPLE_GATTC_WRITE_THROUGHPUT
bool "test the gattc write throughput"
help
If this config item is set, then the 'EXAMPLE_GATTS_NOTIFY_THROUGHPUT' config should be close, it can't
test both write or notify at the same time at this demo
choice EXAMPLE_THROUGHPUT_PHY
prompt "BLE PHY mode"
default EXAMPLE_THROUGHPUT_1M_PHY
help
Define BT BLE PHY mode
config EXAMPLE_THROUGHPUT_1M_PHY
bool "1M PHY"
config EXAMPLE_THROUGHPUT_2M_PHY
bool "2M PHY"
config EXAMPLE_THROUGHPUT_CODED_PHY_S2
bool "Coded PHY S2"
config EXAMPLE_THROUGHPUT_CODED_PHY_S8
bool "Coded PHY S8"
endchoice
config EXAMPLE_THROUGHPUT_PHY
int
default 0 if EXAMPLE_THROUGHPUT_1M_PHY
default 1 if EXAMPLE_THROUGHPUT_2M_PHY
default 2 if EXAMPLE_THROUGHPUT_CODED_PHY_S2
default 3 if EXAMPLE_THROUGHPUT_CODED_PHY_S8
endmenu

View File

@ -0,0 +1,647 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/****************************************************************************
*
* This is the demo to test the BLE throughput. It should be used together with throughput_client demo.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.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_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gatt_common_api.h"
#include "esp_timer.h"
#include "sdkconfig.h"
/**********************************************************
* Thread/Task reference
**********************************************************/
#ifdef CONFIG_BLUEDROID_PINNED_TO_CORE
#define BLUETOOTH_TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY)
#else
#define BLUETOOTH_TASK_PINNED_TO_CORE (0)
#endif
#define SECOND_TO_USECOND 1000000
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
#define GATTS_NOTIFY_LEN 495
static SemaphoreHandle_t gatts_semaphore;
static bool can_send_notify = false;
static uint8_t indicate_data[GATTS_NOTIFY_LEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a};
#endif /* #if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT) */
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
static bool start = false;
static uint64_t write_len = 0;
static uint64_t start_time = 0;
static uint64_t current_time = 0;
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
static bool is_connect = false;
///Declare the static function
static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
#define GATTS_SERVICE_UUID_TEST_A 0x00FF
#define GATTS_CHAR_UUID_TEST_A 0xFF01
#define GATTS_DESCR_UUID_TEST_A 0x3333
#define GATTS_NUM_HANDLE_TEST_A 4
#define GATTS_SERVICE_UUID_TEST_B 0x00EE
#define GATTS_CHAR_UUID_TEST_B 0xEE01
#define GATTS_DESCR_UUID_TEST_B 0x2222
#define GATTS_NUM_HANDLE_TEST_B 4
#define TEST_DEVICE_NAME "THROUGHPUT_PHY_DEMO"
#define TEST_MANUFACTURER_DATA_LEN 17
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
#define EXT_ADV_HANDLE 0
#define NUM_EXT_ADV_SET 1
#define EXT_ADV_DURATION 0
#define EXT_ADV_MAX_EVENTS 0
#define PREPARE_BUF_MAX_SIZE 1024
static const char *GATTS_TAG = "GATTS_DEMO_PHY";
static uint8_t char1_str[] = {0x11,0x22,0x33};
static esp_gatt_char_prop_t a_property = 0;
static esp_attr_value_t gatts_demo_char1_val =
{
.attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
.attr_len = sizeof(char1_str),
.attr_value = char1_str,
};
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',
};
static esp_ble_gap_ext_adv_t ext_adv[1] = {
[0] = {EXT_ADV_HANDLE, EXT_ADV_DURATION, EXT_ADV_MAX_EVENTS},
};
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,
.channel_map = ADV_CHNL_ALL,
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
.primary_phy = ESP_BLE_GAP_PHY_1M,
.max_skip = 0,
#if (CONFIG_EXAMPLE_THROUGHPUT_1M_PHY)
.secondary_phy = ESP_BLE_GAP_PHY_1M,
#elif (CONFIG_EXAMPLE_THROUGHPUT_2M_PHY)
.secondary_phy = ESP_BLE_GAP_PHY_2M,
#else
.secondary_phy = ESP_BLE_GAP_PHY_CODED,
#endif
.sid = 0,
.scan_req_notif = false,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE,
};
#define PROFILE_NUM 1
#define PROFILE_A_APP_ID 0
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;
};
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_A_APP_ID] = {
.gatts_cb = gatts_profile_a_event_handler,
.gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
},
};
typedef struct {
uint8_t *prepare_buf;
int prepare_len;
} prepare_type_env_t;
static prepare_type_env_t a_prepare_write_env;
extern void esp_ble_switch_phy_coded(bool phy_500k);
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
static uint8_t check_sum(uint8_t *addr, uint16_t count)
{
uint32_t sum = 0;
if (addr == NULL || count == 0) {
return 0;
}
for(int i = 0; i < count; i++) {
sum = sum + addr[i];
}
while (sum >> 8) {
sum = (sum & 0xff) + (sum >> 8);
}
return (uint8_t)~sum;
}
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_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
ESP_LOGI(GATTS_TAG,"Extended advertising params set, status %d", param->ext_adv_set_params.status);
esp_ble_gap_config_ext_adv_data_raw(EXT_ADV_HANDLE, sizeof(ext_adv_raw_data), &ext_adv_raw_data[0]);
break;
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
ESP_LOGI(GATTS_TAG,"Extended advertising data set, status %d", param->ext_adv_data_set.status);
esp_ble_gap_ext_adv_start(NUM_EXT_ADV_SET, &ext_adv[0]);
break;
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
ESP_LOGI(GATTS_TAG, "Extended advertising start, status %d", param->ext_adv_data_set.status);
break;
case ESP_GAP_BLE_ADV_TERMINATED_EVT:
ESP_LOGI(GATTS_TAG, "Extended advertising terminated, status %d", param->adv_terminate.status);
if(param->adv_terminate.status == 0x00) {
ESP_LOGI(GATTS_TAG, "Advertising successfully ended with a connection being created");
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(GATTS_TAG, "Connection params update, 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;
}
}
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
esp_gatt_status_t status = ESP_GATT_OK;
if (param->write.need_rsp) {
if (param->write.is_prep) {
if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_OFFSET;
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_ATTR_LEN;
}
if (status == ESP_GATT_OK && prepare_write_env->prepare_buf == NULL) {
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
prepare_write_env->prepare_len = 0;
if (prepare_write_env->prepare_buf == NULL) {
ESP_LOGE(GATTS_TAG, "Gatt_server prep no mem");
status = ESP_GATT_NO_RESOURCES;
}
}
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
if (gatt_rsp) {
gatt_rsp->attr_value.len = param->write.len;
gatt_rsp->attr_value.handle = param->write.handle;
gatt_rsp->attr_value.offset = param->write.offset;
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
if (response_err != ESP_OK) {
ESP_LOGE(GATTS_TAG, "Send response error\n");
}
free(gatt_rsp);
} else {
ESP_LOGE(GATTS_TAG, "malloc failed, no resource to send response error\n");
status = ESP_GATT_NO_RESOURCES;
}
if (status != ESP_GATT_OK) {
return;
}
memcpy(prepare_write_env->prepare_buf + param->write.offset,
param->write.value,
param->write.len);
prepare_write_env->prepare_len += param->write.len;
}else {
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL);
}
}
}
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
if (param->exec_write.exec_write_flag != ESP_GATT_PREP_WRITE_EXEC){
ESP_LOGI(GATTS_TAG,"Prepare write cancel");
}
if (prepare_write_env->prepare_buf) {
free(prepare_write_env->prepare_buf);
prepare_write_env->prepare_buf = NULL;
}
prepare_write_env->prepare_len = 0;
}
static void gatts_profile_a_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_A_APP_ID].service_id.is_primary = true;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A;
gl_profile_tab[PROFILE_A_APP_ID].gatts_if = gatts_if;
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(TEST_DEVICE_NAME);
if (set_dev_name_ret){
ESP_LOGE(GATTS_TAG, "set device name failed, error code = %x", set_dev_name_ret);
}
esp_ble_gap_ext_adv_set_params(EXT_ADV_HANDLE, &ext_adv_params);
esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A);
break;
case ESP_GATTS_READ_EVT: {
ESP_LOGI(GATTS_TAG, "Characteristic read, conn_id %d, trans_id %" PRIu32 ", handle %d", param->read.conn_id, param->read.trans_id, param->read.handle);
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.len = 4;
rsp.attr_value.value[0] = 0xde;
rsp.attr_value.value[1] = 0xed;
rsp.attr_value.value[2] = 0xbe;
rsp.attr_value.value[3] = 0xef;
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
ESP_GATT_OK, &rsp);
break;
}
case ESP_GATTS_WRITE_EVT: {
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
if (!param->write.is_prep){
if (gl_profile_tab[PROFILE_A_APP_ID].descr_handle == param->write.handle && param->write.len == 2){
uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){
if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY){
ESP_LOGI(GATTS_TAG, "Notification enable");
can_send_notify = true;
xSemaphoreGive(gatts_semaphore);
}
}else if (descr_value == 0x0002){
if (a_property & ESP_GATT_CHAR_PROP_BIT_INDICATE){
ESP_LOGI(GATTS_TAG, "Indication enable");
uint8_t indicate_data[600];
for (int i = 0; i < sizeof(indicate_data); ++i)
{
indicate_data[i] = i%0xff;
}
for (int j = 0; j < 1000; j++) {
//the size of indicate_data[] need less than MTU size
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, true);
}
}
}
else if (descr_value == 0x0000){
can_send_notify = false;
a_property = 0;
ESP_LOGI(GATTS_TAG, "Notification/Indication disable");
}else{
ESP_LOGE(GATTS_TAG, "Unknown descriptor value");
ESP_LOG_BUFFER_HEX(GATTS_TAG, param->write.value, param->write.len);
}
}
}
#endif /* #if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT) */
example_write_event_env(gatts_if, &a_prepare_write_env, param);
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
if (param->write.handle == gl_profile_tab[PROFILE_A_APP_ID].char_handle) {
// The last value byte is the checksum data, should used to check the data is received corrected or not.
if (param->write.value[param->write.len - 1] ==
check_sum(param->write.value, param->write.len - 1)) {
write_len += param->write.len;
}
if (start == false) {
start_time = esp_timer_get_time();
start = true;
break;
}
}
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
ESP_LOGI(GATTS_TAG,"Execute write");
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_CANCEL) {
if (write_len > a_prepare_write_env.prepare_len) {
write_len -= a_prepare_write_env.prepare_len;
} else {
write_len = 0;
}
}
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
example_exec_write_event_env(&a_prepare_write_env, param);
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI(GATTS_TAG, "MTU exchange, MTU %d", param->mtu.mtu);
is_connect = true;
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_CREATE_EVT:
ESP_LOGI(GATTS_TAG, "Service create, status %d, service_handle %d", param->create.status, param->create.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A;
esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle);
a_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
esp_err_t add_char_ret = esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
a_property,
&gatts_demo_char1_val, NULL);
if (add_char_ret){
ESP_LOGE(GATTS_TAG, "add char failed, error code =%x",add_char_ret);
}
break;
case ESP_GATTS_ADD_INCL_SRVC_EVT:
break;
case ESP_GATTS_ADD_CHAR_EVT: {
uint16_t length = 0;
const uint8_t *prf_char;
ESP_LOGI(GATTS_TAG, "Characteristic add, status %d, attr_handle %d, service_handle %d",
param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
esp_err_t get_attr_ret = esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char);
if (get_attr_ret == ESP_FAIL){
ESP_LOGE(GATTS_TAG, "ILLEGAL HANDLE");
}
ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x", length);
for(int i = 0; i < length; i++){
ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x",i,prf_char[i]);
}
esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
if (add_descr_ret){
ESP_LOGE(GATTS_TAG, "add char descr failed, error code =%x", add_descr_ret);
}
break;
}
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(GATTS_TAG, "Descriptor add, status %d, attr_handle %d, service_handle %d",
param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(GATTS_TAG, "Service start, status %d, service_handle %d",
param->start.status, param->start.service_handle);
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT: {
ESP_LOGI(GATTS_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id;
break;
}
case ESP_GATTS_DISCONNECT_EVT:
is_connect = false;
ESP_LOGI(GATTS_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%x",
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
esp_ble_gap_ext_adv_start(NUM_EXT_ADV_SET, &ext_adv[0]);
break;
case ESP_GATTS_CONF_EVT:
break;
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
break;
case ESP_GATTS_CONGEST_EVT:
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
if (param->congest.congested) {
can_send_notify = false;
} else {
can_send_notify = true;
xSemaphoreGive(gatts_semaphore);
}
#endif /* #if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT) */
break;
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 is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
gl_profile_tab[param->reg.app_id].gatts_if = gatts_if;
} else {
ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d",
param->reg.app_id,
param->reg.status);
return;
}
}
/* If the gatts_if equal to profile A, call profile A cb handler,
* so here call each profile's callback */
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
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);
}
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
void throughput_server_task(void *param)
{
vTaskDelay(2000 / portTICK_PERIOD_MS);
uint8_t sum = check_sum(indicate_data, sizeof(indicate_data) - 1);
// Added the check sum in the last data value.
indicate_data[GATTS_NOTIFY_LEN - 1] = sum;
while(1) {
if (!can_send_notify) {
int res = xSemaphoreTake(gatts_semaphore, portMAX_DELAY);
assert(res == pdTRUE);
} else {
if (is_connect) {
int free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);
if(free_buff_num > 0) {
for( ; free_buff_num > 0; free_buff_num--) {
esp_ble_gatts_send_indicate(gl_profile_tab[PROFILE_A_APP_ID].gatts_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id,
gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, false);
}
} else { //Add the vTaskDelay to prevent this task from consuming the CPU all the time, causing low-priority tasks to not be executed at all.
vTaskDelay( 10 / portTICK_PERIOD_MS );
}
} else {
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
}
}
#endif
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
void throughput_cal_task(void *param)
{
while (1)
{
uint32_t bit_rate = 0;
vTaskDelay(2000 / portTICK_PERIOD_MS);
if (is_connect && start_time) {
current_time = esp_timer_get_time();
bit_rate = write_len * SECOND_TO_USECOND / (current_time - start_time);
ESP_LOGI(GATTS_TAG, "GATTC write Bit rate = %" PRIu32 " Byte/s, = %" PRIu32 " bit/s, time %d",
bit_rate, bit_rate<<3, (int)((current_time - start_time) / SECOND_TO_USECOND));
}
}
}
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
void app_main(void)
{
esp_err_t ret;
// 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", __func__);
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(GATTS_TAG, "%s enable controller failed", __func__);
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TAG, "%s init bluetooth failed", __func__);
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed", __func__);
return;
}
#if (CONFIG_EXAMPLE_THROUGHPUT_CODED_PHY_S2)
// Should be invoked after the Controller and Host inited and enabled
esp_ble_switch_phy_coded(true);
#endif /*#if (EXAMPLE_THROUGHPUT_CODED_PHY_S2)*/
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_A_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);
}
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
// The task is only created on the CPU core that Bluetooth is working on,
// preventing the sending task from using the un-updated Bluetooth state on another CPU.
xTaskCreatePinnedToCore(&throughput_server_task, "throughput_server_task", 4096, NULL, 15, NULL, BLUETOOTH_TASK_PINNED_TO_CORE);
#endif
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
xTaskCreatePinnedToCore(&throughput_cal_task, "throughput_cal_task", 4096, NULL, 14, NULL, BLUETOOTH_TASK_PINNED_TO_CORE);
#endif
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
gatts_semaphore = xSemaphoreCreateBinary();
if (!gatts_semaphore) {
ESP_LOGE(GATTS_TAG, "%s, init fail, the gatts semaphore create fail.", __func__);
return;
}
#endif /* #if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT) */
return;
}

View File

@ -0,0 +1,11 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT=y
CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT=n
CONFIG_BT_ENABLED=y
CONFIG_EXAMPLE_THROUGHPUT_PHY=0
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=n
# CONFIG_BT_LE_50_FEATURE_SUPPORT is not used on ESP32, ESP32-C3 and ESP32-S3.
# CONFIG_BT_LE_50_FEATURE_SUPPORT=n

View File

@ -0,0 +1,8 @@
# 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_LE_50_FEATURE_SUPPORT=y
CONFIG_BT_LE_HCI_EVT_BUF_SIZE=257
CONFIG_XTAL_FREQ_26=y

View File

@ -0,0 +1,5 @@
# 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="esp32c3"
CONFIG_BT_ENABLED=y

View File

@ -0,0 +1,5 @@
# 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="esp32s3"
CONFIG_BT_ENABLED=y