mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(examples): improve bluedroid BLE example error handling
Check GAP/GATT event status, fix prepare-write buffer lifecycle, and
align example code with updated Bluedroid API behavior.
(cherry picked from commit bfc47ace48)
Co-authored-by: zhiweijian <zhiweijian@espressif.com>
This commit is contained in:
+1
-1
@@ -287,7 +287,7 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
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_TABLE_TAG, "Extended advertising start, status %d", param->ext_adv_data_set.status);
|
||||
ESP_LOGI(GATTS_TABLE_TAG, "Extended advertising start, status %d", param->ext_adv_start.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_ADV_TERMINATED_EVT:
|
||||
ESP_LOGI(GATTS_TABLE_TAG, "Extended advertising terminated, status %d", param->adv_terminate.status);
|
||||
|
||||
+63
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -163,6 +163,9 @@ static uint8_t check_sum(uint8_t *addr, uint16_t count)
|
||||
if (addr == NULL || count == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (count > (ESP_GATT_MAX_MTU_SIZE - 3U)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
sum = sum + addr[i];
|
||||
@@ -175,6 +178,15 @@ static uint8_t check_sum(uint8_t *addr, uint16_t count)
|
||||
return (uint8_t)~sum;
|
||||
}
|
||||
|
||||
static void throughput_client_resume_ext_scan(void)
|
||||
{
|
||||
connect = false;
|
||||
esp_err_t err = esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION, EXT_SCAN_PERIOD);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(GATTC_TAG, "start_ext_scan failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -202,6 +214,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
case ESP_GATTC_OPEN_EVT:
|
||||
if (param->open.status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "Open failed, status %d", p_data->open.status);
|
||||
throughput_client_resume_ext_scan();
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(GATTC_TAG, "Open successfully, MTU %u", param->open.mtu);
|
||||
@@ -293,12 +306,13 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
&count);
|
||||
if (ret_status != ESP_GATT_OK){
|
||||
ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_attr_count error");
|
||||
}
|
||||
if (count > 0){
|
||||
} else if (count == 0) {
|
||||
ESP_LOGE(GATTC_TAG, "decsr not found");
|
||||
} else {
|
||||
descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count);
|
||||
if (!descr_elem_result){
|
||||
if (descr_elem_result == NULL){
|
||||
ESP_LOGE(GATTC_TAG, "malloc error, gattc no mem");
|
||||
}else{
|
||||
} 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,
|
||||
@@ -307,10 +321,10 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
&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){
|
||||
} else 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) {
|
||||
/* Every char has only one descriptor in our 'throughput_server' demo, so we use first 'descr_elem_result' */
|
||||
ret_status = esp_ble_gattc_write_char_descr( gattc_if,
|
||||
gl_profile_tab[PROFILE_A_APP_ID].conn_id,
|
||||
descr_elem_result[0].handle,
|
||||
@@ -318,29 +332,37 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
(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");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
descr_elem_result = NULL;
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (p_data->notify.is_notify) {
|
||||
uint16_t vlen = p_data->notify.value_len;
|
||||
uint8_t *val = p_data->notify.value;
|
||||
/* value_len == 0 makes (vlen - 1) wrap; never index or pass to check_sum before validating. */
|
||||
const uint16_t max_notify_len = (uint16_t)(ESP_GATT_MAX_MTU_SIZE - 3U);
|
||||
if (val == NULL) {
|
||||
ESP_LOGW(GATTC_TAG, "notify ignored: null value");
|
||||
} else if (vlen == 0) {
|
||||
ESP_LOGW(GATTC_TAG, "notify ignored: zero length");
|
||||
} else if (vlen < 2) {
|
||||
ESP_LOGW(GATTC_TAG, "notify ignored: length too short for payload+checksum");
|
||||
} else if (vlen > max_notify_len) {
|
||||
ESP_LOGW(GATTC_TAG, "notify ignored: length exceeds bound");
|
||||
} else if (val[vlen - 1] == check_sum(val, (uint16_t)(vlen - 1U))) {
|
||||
notify_len += vlen;
|
||||
} else {
|
||||
ESP_LOGE(GATTC_TAG, "notify checksum mismatch");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(GATTC_TAG, "Indication received, value:");
|
||||
}
|
||||
@@ -385,8 +407,14 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
current_time = 0;
|
||||
notify_len = 0;
|
||||
#endif /* #if (CONFIG_GATTS_NOTIFY_THROUGHPUT) */
|
||||
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
|
||||
/* Unblock throughput_client_task if it is waiting on gattc_semaphore while congested. */
|
||||
can_send_write = true;
|
||||
xSemaphoreGive(gattc_semaphore);
|
||||
#endif /* #if (CONFIG_GATTC_WRITE_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);
|
||||
throughput_client_resume_ext_scan();
|
||||
break;
|
||||
case ESP_GATTC_CONGEST_EVT:
|
||||
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
|
||||
@@ -517,7 +545,6 @@ static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp
|
||||
#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;
|
||||
|
||||
@@ -619,6 +646,17 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_GATTC_WRITE_THROUGHPUT)
|
||||
/* Create the semaphore before registering the GATTC callback so that any
|
||||
* xSemaphoreGive() invoked from the callback is guaranteed to see a valid handle.
|
||||
*/
|
||||
gattc_semaphore = xSemaphoreCreateBinary();
|
||||
if (gattc_semaphore == NULL) {
|
||||
ESP_LOGE(GATTC_TAG, "%s: gattc semaphore create failed", __func__);
|
||||
return;
|
||||
}
|
||||
#endif /* #if (CONFIG_GATTC_WRITE_THROUGHPUT) */
|
||||
|
||||
//register the callback function to the gattc module
|
||||
ret = esp_ble_gattc_register_callback(esp_gattc_cb);
|
||||
if(ret){
|
||||
@@ -636,20 +674,11 @@ void app_main(void)
|
||||
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.
|
||||
/* Create the task only after the semaphore exists; never rely on priority or delays. */
|
||||
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) */
|
||||
}
|
||||
|
||||
+46
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -164,6 +164,18 @@ typedef struct {
|
||||
|
||||
static prepare_type_env_t a_prepare_write_env;
|
||||
|
||||
static void prepare_write_env_clear(prepare_type_env_t *env)
|
||||
{
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
if (env->prepare_buf != NULL) {
|
||||
free(env->prepare_buf);
|
||||
env->prepare_buf = NULL;
|
||||
}
|
||||
env->prepare_len = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -175,6 +187,9 @@ static uint8_t check_sum(uint8_t *addr, uint16_t count)
|
||||
if (addr == NULL || count == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (count > (ESP_GATT_MAX_MTU_SIZE - 3U)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
sum = sum + addr[i];
|
||||
@@ -228,6 +243,8 @@ void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare
|
||||
status = ESP_GATT_INVALID_OFFSET;
|
||||
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
|
||||
status = ESP_GATT_INVALID_ATTR_LEN;
|
||||
} else if (param->write.len > ESP_GATT_MAX_ATTR_LEN) {
|
||||
status = ESP_GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
|
||||
if (status == ESP_GATT_OK && prepare_write_env->prepare_buf == NULL) {
|
||||
@@ -239,13 +256,19 @@ void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare
|
||||
}
|
||||
}
|
||||
|
||||
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
|
||||
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)calloc(1, 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);
|
||||
if (status == ESP_GATT_OK) {
|
||||
if (param->write.value == NULL) {
|
||||
status = ESP_GATT_INVALID_ATTR_LEN;
|
||||
} else {
|
||||
gatt_rsp->attr_value.len = param->write.len;
|
||||
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) {
|
||||
@@ -275,11 +298,7 @@ void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble
|
||||
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;
|
||||
prepare_write_env_clear(prepare_write_env);
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -356,9 +375,22 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
|
||||
#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;
|
||||
uint16_t wlen = param->write.len;
|
||||
uint8_t *wval = param->write.value;
|
||||
/* len==0 makes (wlen-1) wrap; cap len before indexing or passing to check_sum. */
|
||||
const uint16_t max_write_len = (uint16_t)(ESP_GATT_MAX_MTU_SIZE - 3U);
|
||||
if (wval == NULL) {
|
||||
ESP_LOGW(GATTS_TAG, "write ignored: null value");
|
||||
} else if (wlen == 0) {
|
||||
ESP_LOGW(GATTS_TAG, "write ignored: zero length");
|
||||
} else if (wlen < 2) {
|
||||
ESP_LOGW(GATTS_TAG, "write ignored: length too short for payload+checksum");
|
||||
} else if (wlen > max_write_len) {
|
||||
ESP_LOGW(GATTS_TAG, "write ignored: length exceeds bound");
|
||||
} else if (wval[wlen - 1] == check_sum(wval, (uint16_t)(wlen - 1U))) {
|
||||
write_len += wlen;
|
||||
} else {
|
||||
ESP_LOGE(GATTS_TAG, "write checksum mismatch");
|
||||
}
|
||||
|
||||
if (start == false) {
|
||||
@@ -451,10 +483,12 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
|
||||
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;
|
||||
prepare_write_env_clear(&a_prepare_write_env);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
is_connect = false;
|
||||
prepare_write_env_clear(&a_prepare_write_env);
|
||||
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]);
|
||||
|
||||
@@ -96,6 +96,16 @@ static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Clear connect-in-progress flag and restart indefinite extended scan (after failed open or disconnect). */
|
||||
static void central_resume_ext_scan(void)
|
||||
{
|
||||
connect = false;
|
||||
esp_err_t err = esp_ble_gap_start_ext_scan(0, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "start ext scan failed, error = 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GATT client event handler
|
||||
*/
|
||||
@@ -112,6 +122,10 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
case ESP_GATTC_REG_EVT:
|
||||
ESP_LOGI(TAG, "GATT client register, status %d, app_id %d, gattc_if %d",
|
||||
p_data->reg.status, p_data->reg.app_id, gattc_if);
|
||||
if (p_data->reg.status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "GATT client register failed, status %d", p_data->reg.status);
|
||||
break;
|
||||
}
|
||||
gl_profile_tab[PROFILE_A_APP_ID].gattc_if = gattc_if;
|
||||
// Set default subrate parameters
|
||||
esp_ble_default_subrate_param_t default_subrate_params = {
|
||||
@@ -148,11 +162,19 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
ESP_LOGI(TAG, "Subrate request sent successfully");
|
||||
}
|
||||
break;
|
||||
case ESP_GATTC_OPEN_EVT:
|
||||
if (p_data->open.status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "Open failed, status %d", p_data->open.status);
|
||||
central_resume_ext_scan();
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "GATT open OK, conn_id %d, MTU %u", p_data->open.conn_id, p_data->open.mtu);
|
||||
break;
|
||||
case ESP_GATTC_DISCONNECT_EVT:
|
||||
connect = false;
|
||||
g_conn_handle = 0xFFFF;
|
||||
ESP_LOGI(TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
|
||||
ESP_BD_ADDR_HEX(p_data->disconnect.remote_bda), p_data->disconnect.reason);
|
||||
central_resume_ext_scan();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -208,10 +230,9 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
creat_conn_params.phy_1m_conn_params = &phy_1m_conn_params;
|
||||
creat_conn_params.phy_2m_conn_params = &phy_2m_conn_params;
|
||||
creat_conn_params.phy_coded_conn_params = &phy_coded_conn_params;
|
||||
if (esp_ble_gattc_enh_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, &creat_conn_params) != ESP_OK)
|
||||
{
|
||||
connect = false;
|
||||
if (esp_ble_gattc_enh_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, &creat_conn_params) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open connection");
|
||||
central_resume_ext_scan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-19
@@ -37,6 +37,7 @@
|
||||
#define REMOTE_NOTIFY_UUID 0xFF01
|
||||
#define EXT_SCAN_DURATION 0
|
||||
#define EXT_SCAN_PERIOD 0
|
||||
#define BLE_CONN_HDL_INVALID ((uint16_t)0xFFFF)
|
||||
|
||||
///Declare static functions
|
||||
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
@@ -95,7 +96,7 @@ const esp_ble_conn_params_t phy_coded_conn_params = {
|
||||
|
||||
static uint8_t antenna_ids[2] = {0x00, 0x01};
|
||||
esp_ble_cte_recv_params_params_t cte_recv_params = {
|
||||
.conn_handle = 0xff,
|
||||
.conn_handle = BLE_CONN_HDL_INVALID,
|
||||
.sampling_en = ESP_BLE_CTE_SAMPLING_ENABLE,
|
||||
.slot_dur = ESP_BLE_CTE_SLOT_DURATION_2US,
|
||||
.switching_pattern_len = sizeof(antenna_ids),
|
||||
@@ -103,14 +104,14 @@ esp_ble_cte_recv_params_params_t cte_recv_params = {
|
||||
};
|
||||
|
||||
static esp_ble_cte_req_en_params_t cte_conn_req_en = {
|
||||
.conn_handle = 0xff,
|
||||
.conn_handle = BLE_CONN_HDL_INVALID,
|
||||
.enable = ESP_BLE_CTE_SAMPLING_ENABLE,
|
||||
.cte_req_interval = 0x05,
|
||||
.req_cte_len = ESP_BLE_CTE_MAX_REQUESTED_CTE_LENGTH,
|
||||
.req_cte_Type = ESP_BLE_CTE_TYPE_AOA,
|
||||
};
|
||||
|
||||
uint16_t cur_conn_hdl = 0xff;
|
||||
uint16_t cur_conn_hdl = BLE_CONN_HDL_INVALID;
|
||||
|
||||
#define PROFILE_NUM 1
|
||||
#define PROFILE_A_APP_ID 0
|
||||
@@ -210,6 +211,31 @@ static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req)
|
||||
return auth_str;
|
||||
}
|
||||
|
||||
/** After a failed open or disconnect: clear connect flag and restart extended scan. */
|
||||
static void cte_resume_ext_scan(void)
|
||||
{
|
||||
connect = false;
|
||||
esp_err_t err = esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION, EXT_SCAN_PERIOD);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "start ext scan failed, error = 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
/** Start CTE receive setup only after link is authenticated (see esp_gap_cb AUTH_CMPL). */
|
||||
static void cte_enable_connection_receive_after_encrypted(void)
|
||||
{
|
||||
if (cur_conn_hdl == BLE_CONN_HDL_INVALID) {
|
||||
ESP_LOGW(LOG_TAG, "Skip CTE receive params: no connection handle");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(LOG_TAG, "Set CTE connection receive params after encryption, conn_handle %d", cur_conn_hdl);
|
||||
cte_recv_params.conn_handle = cur_conn_hdl;
|
||||
esp_err_t cte_ret = esp_ble_cte_set_connection_receive_params(&cte_recv_params);
|
||||
if (cte_ret != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "CTE set connection receive params failed, 0x%x", cte_ret);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -227,6 +253,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
case ESP_GATTC_OPEN_EVT:
|
||||
if (param->open.status != ESP_GATT_OK){
|
||||
ESP_LOGE(LOG_TAG, "Open failed, status %x", p_data->open.status);
|
||||
cte_resume_ext_scan();
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(LOG_TAG, "Open successfully, MTU %d", p_data->open.mtu);
|
||||
@@ -239,19 +266,14 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
break;
|
||||
case ESP_GATTC_CFG_MTU_EVT:
|
||||
ESP_LOGI(LOG_TAG, "MTU exchange, status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id);
|
||||
if (!param->cfg_mtu.status) {
|
||||
ESP_LOGI(LOG_TAG, "Set CTE connection receive params, conn_handle %d", cur_conn_hdl);
|
||||
cte_recv_params.conn_handle = cur_conn_hdl;
|
||||
esp_ble_cte_set_connection_receive_params(&cte_recv_params);
|
||||
}
|
||||
break;
|
||||
case ESP_GATTC_DIS_SRVC_CMPL_EVT:
|
||||
if (param->dis_srvc_cmpl.status != ESP_GATT_OK){
|
||||
ESP_LOGE(LOG_TAG, "Service discover failed, status %d", param->dis_srvc_cmpl.status);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(LOG_TAG, "Service discover complete, conn_id %d", param->dis_srvc_cmpl.conn_id);
|
||||
esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid);
|
||||
ESP_LOGI(LOG_TAG, "Service discover complete, conn_id %d", p_data->dis_srvc_cmpl.conn_id);
|
||||
esp_ble_gattc_search_service(gattc_if, p_data->dis_srvc_cmpl.conn_id, &remote_filter_service_uuid);
|
||||
break;
|
||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||
ESP_LOGI(LOG_TAG, "Service search result, conn_id %x, is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
|
||||
@@ -314,9 +336,9 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
case ESP_GATTC_DISCONNECT_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
|
||||
ESP_BD_ADDR_HEX(p_data->disconnect.remote_bda), p_data->disconnect.reason);
|
||||
connect = false;
|
||||
get_service = false;
|
||||
esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION, EXT_SCAN_PERIOD);
|
||||
cur_conn_hdl = BLE_CONN_HDL_INVALID;
|
||||
cte_resume_ext_scan();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -397,8 +419,7 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
ESP_LOGI(LOG_TAG, "Pairing failed, reason 0x%x",param->ble_security.auth_cmpl.fail_reason);
|
||||
} else {
|
||||
ESP_LOGI(LOG_TAG, "Pairing successfully, auth mode %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode));
|
||||
// Enable CTE
|
||||
|
||||
cte_enable_connection_receive_after_encrypted();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -429,7 +450,10 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
creat_conn_params.phy_1m_conn_params = &phy_1m_conn_params;
|
||||
creat_conn_params.phy_2m_conn_params = &phy_2m_conn_params;
|
||||
creat_conn_params.phy_coded_conn_params = &phy_coded_conn_params;
|
||||
esp_ble_gattc_enh_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, &creat_conn_params);
|
||||
if (esp_ble_gattc_enh_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, &creat_conn_params) != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "Failed to open connection");
|
||||
cte_resume_ext_scan();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -453,14 +477,17 @@ static void cte_event_handler(esp_ble_cte_cb_event_t event, esp_ble_cte_cb_param
|
||||
case ESP_BLE_CTE_SET_CONN_TRANS_PARAMS_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection transmit params, status %d", param->conn_trans_params_cmpl.status);
|
||||
break;
|
||||
case ESP_BLE_CTE_SET_CONN_RECV_PARAMS_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection receive params, status %d", param->conn_recv_params_cmpl.status);
|
||||
case ESP_BLE_CTE_SET_CONN_RECV_PARAMS_CMPL_EVT: {
|
||||
uint16_t recv_cmpl_conn_hdl = param->conn_recv_params_cmpl.conn_handle;
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection receive params, status %d, conn_handle %d",
|
||||
param->conn_recv_params_cmpl.status, recv_cmpl_conn_hdl);
|
||||
if (!param->conn_recv_params_cmpl.status) {
|
||||
cte_conn_req_en.conn_handle = cur_conn_hdl;
|
||||
ESP_LOGI(LOG_TAG, "Enable CTE request, conn_handle %d", cur_conn_hdl);
|
||||
cte_conn_req_en.conn_handle = recv_cmpl_conn_hdl;
|
||||
ESP_LOGI(LOG_TAG, "Enable CTE request, conn_handle %d", recv_cmpl_conn_hdl);
|
||||
esp_ble_cte_connection_cte_request_enable(&cte_conn_req_en);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_CTE_SET_CONN_REQ_ENABLE_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection request enable, status %d", param->conn_req_en_cmpl.status);
|
||||
break;
|
||||
|
||||
+29
-19
@@ -35,6 +35,9 @@
|
||||
|
||||
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
|
||||
|
||||
/* Connection_Handle is 12-bit (0x0000..0x0EFF); 0xFFFF is outside the valid range. */
|
||||
#define BLE_CONN_HDL_INVALID ((uint16_t)0xFFFF)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
@@ -68,18 +71,18 @@ esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
|
||||
|
||||
static uint8_t antenna_ids[2] = {0x00, 0x01};
|
||||
static esp_ble_cte_conn_trans_params_t cte_conn_trans_params = {
|
||||
.conn_handle = 0xff,
|
||||
.conn_handle = BLE_CONN_HDL_INVALID,
|
||||
.cte_types = ESP_BLE_CTE_TYPES_ALL,
|
||||
.switching_pattern_len = sizeof(antenna_ids),
|
||||
.antenna_ids = &antenna_ids[0],
|
||||
};
|
||||
|
||||
static esp_ble_cte_rsp_en_params_t cte_conn_rsp_en = {
|
||||
.conn_handle = 0xff,
|
||||
.conn_handle = BLE_CONN_HDL_INVALID,
|
||||
.enable = ESP_BLE_CTE_RESPONSE_FOR_CONNECTION_ENABLE,
|
||||
};
|
||||
|
||||
uint16_t cur_conn_hdl = 0xff;
|
||||
uint16_t cur_conn_hdl = BLE_CONN_HDL_INVALID;
|
||||
|
||||
struct gatts_profile_inst {
|
||||
esp_gatts_cb_t gatts_cb;
|
||||
@@ -315,10 +318,14 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
ESP_LOGI(LOG_TAG, "Pairing failed, reason 0x%x",param->ble_security.auth_cmpl.fail_reason);
|
||||
} else {
|
||||
ESP_LOGI(LOG_TAG, "Pairing successfully, auth_mode %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode));
|
||||
// Setting CTE connection transmit parameters
|
||||
cte_conn_trans_params.conn_handle = cur_conn_hdl;
|
||||
ESP_LOGI(LOG_TAG, "Set CTE connection transmit params, conn_handle %d", cur_conn_hdl);
|
||||
esp_ble_cte_set_connection_transmit_params(&cte_conn_trans_params);
|
||||
if (cur_conn_hdl != BLE_CONN_HDL_INVALID) {
|
||||
// Setting CTE connection transmit parameters
|
||||
cte_conn_trans_params.conn_handle = cur_conn_hdl;
|
||||
ESP_LOGI(LOG_TAG, "Set CTE connection transmit params, conn_handle %d", cur_conn_hdl);
|
||||
esp_ble_cte_set_connection_transmit_params(&cte_conn_trans_params);
|
||||
} else {
|
||||
ESP_LOGW(LOG_TAG, "Skip CTE transmit params: no active connection handle");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -385,6 +392,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%x",
|
||||
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
|
||||
cur_conn_hdl = BLE_CONN_HDL_INVALID;
|
||||
/* start advertising again when missing the connect */
|
||||
esp_ble_gap_ext_adv_start(NUM_EXT_ADV_SET, &ext_adv[0]);
|
||||
break;
|
||||
@@ -399,18 +407,18 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
|
||||
case ESP_GATTS_CONGEST_EVT:
|
||||
break;
|
||||
case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
|
||||
if (param->create.status == ESP_GATT_OK){
|
||||
if(param->add_attr_tab.num_handle == HRS_IDX_NB) {
|
||||
if (param->add_attr_tab.status == ESP_GATT_OK) {
|
||||
if (param->add_attr_tab.num_handle == HRS_IDX_NB) {
|
||||
ESP_LOGI(LOG_TAG, "Attribute table create successfully, num_handle %x", param->add_attr_tab.num_handle);
|
||||
memcpy(profile_handle_table, param->add_attr_tab.handles,
|
||||
sizeof(profile_handle_table));
|
||||
sizeof(profile_handle_table));
|
||||
esp_ble_gatts_start_service(profile_handle_table[IDX_SVC]);
|
||||
}else{
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "Attribute table create abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)",
|
||||
param->add_attr_tab.num_handle, HRS_IDX_NB);
|
||||
param->add_attr_tab.num_handle, HRS_IDX_NB);
|
||||
}
|
||||
}else{
|
||||
ESP_LOGE(LOG_TAG, "Attribute table create failed, status %x", param->create.status);
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "Attribute table create failed, status %x", param->add_attr_tab.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -422,15 +430,17 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
|
||||
static void cte_event_handler(esp_ble_cte_cb_event_t event, esp_ble_cte_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_BLE_CTE_SET_CONN_TRANS_PARAMS_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection transmit params, status %d", param->conn_trans_params_cmpl.status);
|
||||
case ESP_BLE_CTE_SET_CONN_TRANS_PARAMS_CMPL_EVT: {
|
||||
uint16_t trans_cmpl_conn_hdl = param->conn_trans_params_cmpl.conn_handle;
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection transmit params, status %d, conn_handle %d",
|
||||
param->conn_trans_params_cmpl.status, trans_cmpl_conn_hdl);
|
||||
if (!param->conn_trans_params_cmpl.status) {
|
||||
ESP_LOGI(LOG_TAG, "Setting CTE connection response enable");
|
||||
// Enable CTE response for connection
|
||||
cte_conn_rsp_en.conn_handle = cur_conn_hdl;
|
||||
ESP_LOGI(LOG_TAG, "Setting CTE connection response enable, conn_handle %d", trans_cmpl_conn_hdl);
|
||||
cte_conn_rsp_en.conn_handle = trans_cmpl_conn_hdl;
|
||||
esp_ble_cte_connection_cte_response_enable(&cte_conn_rsp_en);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_CTE_SET_CONN_RECV_PARAMS_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "CTE set connection receive params, status %d", param->conn_recv_params_cmpl.status);
|
||||
break;
|
||||
|
||||
@@ -223,7 +223,11 @@ static void start_periodic_adv(void)
|
||||
{
|
||||
// Create static random address
|
||||
esp_bd_addr_t rand_addr;
|
||||
esp_ble_gap_addr_create_static(rand_addr);
|
||||
esp_err_t addr_ret = esp_ble_gap_addr_create_static(rand_addr);
|
||||
if (addr_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_addr_create_static failed: %s", esp_err_to_name(addr_ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOG_BUFFER_HEX(TAG, rand_addr, ESP_BD_ADDR_LEN);
|
||||
|
||||
|
||||
+3
-1
@@ -243,7 +243,9 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
param->ext_adv_report.params.adv_data_len,
|
||||
ESP_BLE_AD_TYPE_NAME_CMPL,
|
||||
&adv_name_len);
|
||||
if ((adv_name != NULL) && (memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
if ((adv_name != NULL) && (adv_name_len > 0) &&
|
||||
(adv_name_len == strlen(remote_device_name)) &&
|
||||
(memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
// Note: If there are multiple devices with the same device name, the device may sync to an unintended one.
|
||||
// It is recommended to change the default device name to ensure it is unique.
|
||||
periodic_sync = true;
|
||||
|
||||
+33
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -41,16 +41,21 @@
|
||||
#define FUNC_SEND_WAIT_SEM(func, sem) do {\
|
||||
esp_err_t __err_rc = (func);\
|
||||
if (__err_rc != ESP_OK) { \
|
||||
ESP_LOGE(LOG_TAG, "%s, message send fail, error = %d", __func__, __err_rc); \
|
||||
ESP_LOGE(LOG_TAG, "%s failed: %s", #func, esp_err_to_name(__err_rc)); \
|
||||
return; \
|
||||
} \
|
||||
xSemaphoreTake((sem), portMAX_DELAY); \
|
||||
if (last_ble_async_status != ESP_BT_STATUS_SUCCESS) { \
|
||||
ESP_LOGE(LOG_TAG, "Async completion after %s failed, status 0x%x", #func, last_ble_async_status); \
|
||||
return; \
|
||||
} \
|
||||
xSemaphoreTake(sem, portMAX_DELAY); \
|
||||
} while(0);
|
||||
|
||||
#define EXT_ADV_HANDLE 0
|
||||
#define NUM_EXT_ADV 1
|
||||
|
||||
static SemaphoreHandle_t test_sem = NULL;
|
||||
|
||||
static esp_bt_status_t last_ble_async_status = ESP_BT_STATUS_SUCCESS;
|
||||
|
||||
uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02};
|
||||
|
||||
@@ -113,44 +118,56 @@ static esp_ble_cte_trans_enable_params_t cte_trans_enable = {
|
||||
|
||||
static uint8_t periodic_adv_hdl = 0xff;
|
||||
|
||||
static void ble_async_complete_signal(esp_bt_status_t status)
|
||||
{
|
||||
last_ble_async_status = status;
|
||||
if (test_sem != NULL) {
|
||||
xSemaphoreGive(test_sem);
|
||||
}
|
||||
}
|
||||
|
||||
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_RAND_ADDR_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->ext_adv_set_rand_addr.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext_adv_set_rand_addr.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->ext_adv_set_params.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_adv_set_params.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->ext_adv_data_set.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_data_set.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->scan_rsp_set.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->scan_rsp_set.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->ext_adv_start.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_start.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->ext_adv_stop.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
periodic_adv_hdl = param->peroid_adv_set_params.instance;
|
||||
xSemaphoreGive(test_sem);
|
||||
if (param->peroid_adv_set_params.status == ESP_BT_STATUS_SUCCESS) {
|
||||
periodic_adv_hdl = param->peroid_adv_set_params.instance;
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "periodic adv set params failed, not updating periodic_adv_hdl");
|
||||
}
|
||||
ble_async_complete_signal(param->peroid_adv_set_params.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->peroid_adv_set_params.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->period_adv_data_set.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d", param->period_adv_data_set.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->period_adv_start.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d", param->period_adv_start.status);
|
||||
break;
|
||||
default:
|
||||
@@ -162,11 +179,11 @@ static void cte_event_handler(esp_ble_cte_cb_event_t event, esp_ble_cte_cb_param
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_BLE_CTE_SET_CONNLESS_TRANS_PARAMS_CMPL_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->set_trans_params_cmpl.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_BLE_CTE_SET_CONNLESS_TRANS_PARAMS_CMPL_EVT, status %d", param->set_trans_params_cmpl.status);
|
||||
break;
|
||||
case ESP_BLE_CTE_SET_CONNLESS_TRANS_ENABLE_CMPL_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ble_async_complete_signal(param->set_trans_enable_cmpl.status);
|
||||
ESP_LOGI(LOG_TAG, "ESP_BLE_CTE_SET_CONNLESS_TRANS_ENABLE_CMPL_EVT, status %d", param->set_trans_enable_cmpl.status);
|
||||
break;
|
||||
case ESP_BLE_CTE_SET_CONNLESS_IQ_SAMPLING_ENABLE_CMPL_EVT:
|
||||
|
||||
+13
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -37,15 +37,16 @@
|
||||
#include "esp_ble_cte_api.h"
|
||||
|
||||
|
||||
#define LOG_TAG "PERIODIC_SYNC"
|
||||
|
||||
#define FUNC_SEND_WAIT_SEM(func, sem) do {\
|
||||
esp_err_t __err_rc = (func);\
|
||||
if (__err_rc != ESP_OK) { \
|
||||
ESP_LOGE(LOG_TAG, "%s, message send fail, error = %d", __func__, __err_rc); \
|
||||
ESP_LOGE(LOG_TAG, "%s failed: %s", #func, esp_err_to_name(__err_rc)); \
|
||||
return; \
|
||||
} \
|
||||
xSemaphoreTake(sem, portMAX_DELAY); \
|
||||
xSemaphoreTake((sem), portMAX_DELAY); \
|
||||
} while(0);
|
||||
|
||||
#define LOG_TAG "PERIODIC_SYNC"
|
||||
#define EXT_SCAN_DURATION 0
|
||||
#define EXT_SCAN_PERIOD 0
|
||||
|
||||
@@ -136,13 +137,16 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
param->ext_adv_report.params.adv_data_len,
|
||||
ESP_BLE_AD_TYPE_NAME_CMPL,
|
||||
&adv_name_len);
|
||||
if ((adv_name != NULL) && (memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
const size_t remote_cap = sizeof(remote_device_name);
|
||||
size_t remote_len = strnlen(remote_device_name, remote_cap);
|
||||
if ((adv_name != NULL) && (adv_name_len > 0) &&
|
||||
(adv_name_len <= remote_cap) &&
|
||||
(adv_name_len == remote_len) &&
|
||||
(memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
// Note: If there are multiple devices with the same device name, the device may sync to an unintended one.
|
||||
// It is recommended to change the default device name to ensure it is unique.
|
||||
periodic_sync = true;
|
||||
char adv_temp_name[30] = {'0'};
|
||||
memcpy(adv_temp_name, adv_name, adv_name_len);
|
||||
ESP_LOGI(LOG_TAG, "Create sync with the peer device %s", adv_temp_name);
|
||||
ESP_LOGI(LOG_TAG, "Create sync with the peer device %.*s", (int)adv_name_len, (const char *)adv_name);
|
||||
periodic_adv_sync_params.sid = param->ext_adv_report.params.sid;
|
||||
periodic_adv_sync_params.addr_type = param->ext_adv_report.params.addr_type;
|
||||
memcpy(periodic_adv_sync_params.addr, param->ext_adv_report.params.addr, sizeof(esp_bd_addr_t));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -180,12 +180,12 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
}
|
||||
break;
|
||||
case ESP_GATTC_CONNECT_EVT:
|
||||
ESP_LOGI(TAG, "Connected, conn_id %d, remote "ESP_BD_ADDR_STR"",
|
||||
p_data->connect.conn_id, ESP_BD_ADDR_HEX(p_data->connect.remote_bda));
|
||||
ESP_LOGI(TAG, "Connected, conn_id %d, hci_conn_handle %d, remote "ESP_BD_ADDR_STR"",
|
||||
p_data->connect.conn_id, p_data->connect.conn_handle,
|
||||
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));
|
||||
conn_handle = p_data->connect.conn_id;
|
||||
// Initialize power control after connection
|
||||
conn_handle = p_data->connect.conn_handle;
|
||||
init_power_control(conn_handle);
|
||||
break;
|
||||
case ESP_GATTC_DISCONNECT_EVT:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -40,9 +40,10 @@
|
||||
#define FUNC_SEND_WAIT_SEM(func, sem) do {\
|
||||
esp_err_t __err_rc = (func);\
|
||||
if (__err_rc != ESP_OK) { \
|
||||
ESP_LOGE(LOG_TAG, "%s, message send fail, error = %d", __func__, __err_rc); \
|
||||
ESP_LOGE(LOG_TAG, "%s failed: %s", #func, esp_err_to_name(__err_rc)); \
|
||||
return; \
|
||||
} \
|
||||
xSemaphoreTake(sem, portMAX_DELAY); \
|
||||
xSemaphoreTake((sem), portMAX_DELAY); \
|
||||
} while(0);
|
||||
|
||||
#define EXT_ADV_HANDLE 0
|
||||
@@ -95,43 +96,50 @@ static esp_ble_gap_ext_adv_t ext_adv[1] = {
|
||||
[0] = {EXT_ADV_HANDLE, 0, 0},
|
||||
};
|
||||
|
||||
static void periodic_adv_gap_sem_give(void)
|
||||
{
|
||||
if (test_sem != NULL) {
|
||||
xSemaphoreGive(test_sem);
|
||||
}
|
||||
}
|
||||
|
||||
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_RAND_ADDR_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising random address set, status %d, instance %d", param->ext_adv_set_rand_addr.status, param->ext_adv_set_rand_addr.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising params set, status %d, instance %d", param->ext_adv_set_params.status, param->ext_adv_set_params.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising data set, status %d, instance %d", param->ext_adv_data_set.status, param->ext_adv_data_set.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising scan response data set, status %d, instance %d", param->scan_rsp_set.status, param->scan_rsp_set.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising start, status %d, instance numble %d", param->ext_adv_start.status, param->ext_adv_start.instance_num);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising start, status %d, instance number %d", param->ext_adv_start.status, param->ext_adv_start.instance_num);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising start, status %d, instance numble %d", param->ext_adv_stop.status, param->ext_adv_stop.instance_num);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Extended advertising stop, status %d, instance number %d", param->ext_adv_stop.status, param->ext_adv_stop.instance_num);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising params set, status %d, instance %d", param->peroid_adv_set_params.status, param->peroid_adv_set_params.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising data set, status %d, instance %d", param->period_adv_data_set.status, param->period_adv_data_set.instance);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
periodic_adv_gap_sem_give();
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising start, status %d, instance %d", param->period_adv_start.status, param->period_adv_start.instance);
|
||||
break;
|
||||
default:
|
||||
@@ -185,9 +193,18 @@ void app_main(void)
|
||||
ESP_LOGE(LOG_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
test_sem = xSemaphoreCreateBinary();
|
||||
if (test_sem == NULL) {
|
||||
ESP_LOGE(LOG_TAG, "Failed to create semaphore");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (ret){
|
||||
ESP_LOGE(LOG_TAG, "gap register error, error code = %x", ret);
|
||||
vSemaphoreDelete(test_sem);
|
||||
test_sem = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,8 +212,6 @@ void app_main(void)
|
||||
esp_bd_addr_t rand_addr;
|
||||
esp_ble_gap_addr_create_static(rand_addr);
|
||||
|
||||
test_sem = xSemaphoreCreateBinary();
|
||||
|
||||
// 2M phy extend adv, Non-Connectable and Non-Scannable Undirected advertising
|
||||
ESP_LOG_BUFFER_HEX(LOG_TAG, rand_addr, ESP_BD_ADDR_LEN);
|
||||
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(EXT_ADV_HANDLE, &ext_adv_params_2M), test_sem);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -84,10 +84,13 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT:
|
||||
xSemaphoreGive(test_sem);
|
||||
ESP_LOGI(LOG_TAG, "Extended scanning stop, status %d", param->period_adv_stop.status);
|
||||
ESP_LOGI(LOG_TAG, "Extended scanning stop, status %d", param->ext_scan_stop.status);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising create sync, status %d", param->period_adv_create_sync.status);
|
||||
if (param->period_adv_create_sync.status != ESP_BT_STATUS_SUCCESS) {
|
||||
periodic_sync = false;
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising sync cancel, status %d", param->period_adv_sync_cancel.status);
|
||||
@@ -97,9 +100,13 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising sync lost, sync handle %d", param->periodic_adv_sync_lost.sync_handle);
|
||||
periodic_sync = false;
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT:
|
||||
ESP_LOGI(LOG_TAG, "Periodic advertising sync establish, status %d", param->periodic_adv_sync_estab.status);
|
||||
if (param->periodic_adv_sync_estab.status != ESP_BT_STATUS_SUCCESS) {
|
||||
periodic_sync = false;
|
||||
}
|
||||
ESP_LOGI(LOG_TAG, "address "ESP_BD_ADDR_STR"", ESP_BD_ADDR_HEX(param->periodic_adv_sync_estab.adv_addr));
|
||||
ESP_LOGI(LOG_TAG, "sync handle %d sid %d perioic adv interval %d adv phy %d", param->periodic_adv_sync_estab.sync_handle,
|
||||
param->periodic_adv_sync_estab.sid,
|
||||
@@ -113,13 +120,16 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
param->ext_adv_report.params.adv_data_len,
|
||||
ESP_BLE_AD_TYPE_NAME_CMPL,
|
||||
&adv_name_len);
|
||||
if ((adv_name != NULL) && (memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
const size_t remote_cap = sizeof(remote_device_name);
|
||||
size_t remote_len = strnlen(remote_device_name, remote_cap);
|
||||
if ((adv_name != NULL) && (adv_name_len > 0) &&
|
||||
(adv_name_len <= remote_cap) &&
|
||||
(adv_name_len == remote_len) &&
|
||||
(memcmp(adv_name, remote_device_name, adv_name_len) == 0) && !periodic_sync) {
|
||||
// Note: If there are multiple devices with the same device name, the device may sync to an unintended one.
|
||||
// It is recommended to change the default device name to ensure it is unique.
|
||||
periodic_sync = true;
|
||||
char adv_temp_name[30] = {'0'};
|
||||
memcpy(adv_temp_name, adv_name, adv_name_len);
|
||||
ESP_LOGI(LOG_TAG, "Create sync with the peer device %s", adv_temp_name);
|
||||
ESP_LOGI(LOG_TAG, "Create sync with the peer device %.*s", (int)adv_name_len, (const char *)adv_name);
|
||||
periodic_adv_sync_params.sid = param->ext_adv_report.params.sid;
|
||||
periodic_adv_sync_params.addr_type = param->ext_adv_report.params.addr_type;
|
||||
memcpy(periodic_adv_sync_params.addr, param->ext_adv_report.params.addr, sizeof(esp_bd_addr_t));
|
||||
|
||||
Reference in New Issue
Block a user