mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 09:39:10 -04:00
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:
parent
aa07a85df2
commit
28e1524c7e
@ -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)
|
@ -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.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "example_ble_client_throughput.c"
|
||||
INCLUDE_DIRS ".")
|
@ -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
|
@ -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 *)¬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 */
|
||||
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) */
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
@ -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.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "example_ble_server_throughput.c"
|
||||
INCLUDE_DIRS ".")
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user