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:
+47
-17
@@ -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
|
||||
*/
|
||||
@@ -126,6 +126,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];
|
||||
@@ -288,6 +291,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
|
||||
/* free descr_elem_result */
|
||||
free(descr_elem_result);
|
||||
descr_elem_result = NULL;
|
||||
}
|
||||
}
|
||||
else{
|
||||
@@ -299,10 +303,23 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
}
|
||||
case ESP_GATTC_NOTIFY_EVT: {
|
||||
#if (CONFIG_EXAMPLE_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;
|
||||
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:");
|
||||
}
|
||||
@@ -347,6 +364,11 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
current_time = 0;
|
||||
notify_len = 0;
|
||||
#endif /* #if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT) */
|
||||
#if (CONFIG_EXAMPLE_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_EXAMPLE_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);
|
||||
break;
|
||||
@@ -405,7 +427,7 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
|
||||
esp_ble_conn_params_t phy_1m_conn_params = {0};
|
||||
#if(CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT && CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
|
||||
phy_1m_conn_params.interval_max = 34;
|
||||
phy_1m_conn_params.interval_min = 34;
|
||||
phy_1m_conn_params.interval_max = 34;
|
||||
#else
|
||||
phy_1m_conn_params.interval_max = 32;
|
||||
@@ -540,9 +562,14 @@ static void throughput_cal_task(void *param)
|
||||
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));
|
||||
uint64_t elapsed_us = current_time - start_time;
|
||||
if (elapsed_us > 0) {
|
||||
bit_rate = (uint32_t)(notify_len * SECOND_TO_USECOND / elapsed_us);
|
||||
ESP_LOGI(GATTC_TAG, "Notify Bit rate = %" PRIu32 " Byte/s, = %" PRIu32 " bit/s, time = %ds",
|
||||
bit_rate, bit_rate << 3, (int)(elapsed_us / SECOND_TO_USECOND));
|
||||
} else {
|
||||
ESP_LOGI(GATTC_TAG, "Notify Bit rate = 0 Byte/s, = 0 bit/s (elapsed 0 us)");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(GATTC_TAG, "Notify Bit rate = 0 Byte/s, = 0 bit/s");
|
||||
}
|
||||
@@ -601,6 +628,17 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_EXAMPLE_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) {
|
||||
ESP_LOGE(GATTC_TAG, "%s, init fail, the gattc semaphore create fail.", __func__);
|
||||
return;
|
||||
}
|
||||
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
|
||||
|
||||
//register the callback function to the gattc module
|
||||
ret = esp_ble_gattc_register_callback(esp_gattc_cb);
|
||||
if(ret){
|
||||
@@ -626,12 +664,4 @@ void app_main(void)
|
||||
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
|
||||
xTaskCreatePinnedToCore(&throughput_cal_task, "throughput_cal_task", 4096, NULL, 9, NULL, BLUETOOTH_TASK_PINNED_TO_CORE);
|
||||
#endif
|
||||
|
||||
#if (CONFIG_EXAMPLE_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_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
|
||||
}
|
||||
|
||||
+84
-16
@@ -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
|
||||
*/
|
||||
@@ -59,6 +59,7 @@ static bool start = false;
|
||||
static uint64_t write_len = 0;
|
||||
static uint64_t start_time = 0;
|
||||
static uint64_t current_time = 0;
|
||||
static portMUX_TYPE s_write_throughput_stats_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
|
||||
|
||||
static bool is_connect = false;
|
||||
@@ -204,6 +205,18 @@ static prepare_type_env_t a_prepare_write_env;
|
||||
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 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;
|
||||
}
|
||||
|
||||
static uint8_t check_sum(uint8_t *addr, uint16_t count)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
@@ -211,6 +224,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];
|
||||
@@ -334,14 +350,14 @@ void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare
|
||||
}
|
||||
|
||||
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
|
||||
if (prepare_write_env == NULL) {
|
||||
ESP_LOGE(GATTS_TAG, "exec_write: prepare_write_env is NULL");
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
@@ -442,17 +458,32 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
|
||||
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;
|
||||
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))) {
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
write_len += wlen;
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
} else {
|
||||
ESP_LOGE(GATTS_TAG, "write checksum mismatch");
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
if (start == false) {
|
||||
start_time = esp_timer_get_time();
|
||||
start = true;
|
||||
break;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
}
|
||||
#endif /* #if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT) */
|
||||
|
||||
@@ -462,11 +493,13 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
|
||||
ESP_LOGI(GATTS_TAG,"Execute write");
|
||||
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_CANCEL) {
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
if (write_len > a_prepare_write_env.prepare_len) {
|
||||
write_len -= a_prepare_write_env.prepare_len;
|
||||
} else {
|
||||
write_len = 0;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
}
|
||||
#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);
|
||||
@@ -538,10 +571,34 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
|
||||
ESP_LOGI(GATTS_TAG, "Connected, conn_id %d, 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);
|
||||
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
write_len = 0;
|
||||
start_time = 0;
|
||||
start = false;
|
||||
current_time = 0;
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
#endif
|
||||
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
|
||||
can_send_notify = false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
is_connect = false;
|
||||
prepare_write_env_clear(&a_prepare_write_env);
|
||||
#if (CONFIG_EXAMPLE_GATTC_WRITE_THROUGHPUT)
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
write_len = 0;
|
||||
start_time = 0;
|
||||
start = false;
|
||||
current_time = 0;
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
#endif
|
||||
#if (CONFIG_EXAMPLE_GATTS_NOTIFY_THROUGHPUT)
|
||||
can_send_notify = false;
|
||||
#endif
|
||||
ESP_LOGI(GATTS_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
|
||||
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
@@ -637,11 +694,22 @@ void throughput_cal_task(void *param)
|
||||
{
|
||||
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));
|
||||
if (is_connect) {
|
||||
uint64_t snap_write_len;
|
||||
uint64_t snap_start_time;
|
||||
portENTER_CRITICAL(&s_write_throughput_stats_mux);
|
||||
snap_start_time = start_time;
|
||||
snap_write_len = write_len;
|
||||
portEXIT_CRITICAL(&s_write_throughput_stats_mux);
|
||||
if (snap_start_time != 0) {
|
||||
current_time = esp_timer_get_time();
|
||||
uint64_t elapsed_us = current_time - snap_start_time;
|
||||
if (elapsed_us > 0) {
|
||||
bit_rate = (uint32_t)(snap_write_len * SECOND_TO_USECOND / elapsed_us);
|
||||
ESP_LOGI(GATTS_TAG, "GATTC write Bit rate = %" PRIu32 " Byte/s, = %" PRIu32 " bit/s, time %d",
|
||||
bit_rate, bit_rate << 3, (int)(elapsed_us / SECOND_TO_USECOND));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user