diff --git a/components/bt/host/bluedroid/api/esp_gattc_api.c b/components/bt/host/bluedroid/api/esp_gattc_api.c index f54deb8ea2..f296431ddf 100644 --- a/components/bt/host/bluedroid/api/esp_gattc_api.c +++ b/components/bt/host/bluedroid/api/esp_gattc_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -326,6 +326,27 @@ esp_err_t esp_ble_gattc_close (esp_gatt_if_t gattc_if, uint16_t conn_id) return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gattc_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_gattc_cancel_open(const esp_ble_gattc_cancel_open_params_t *params) +{ + btc_msg_t msg = {0}; + btc_ble_gattc_args_t arg; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + if (params == NULL) { + return ESP_ERR_INVALID_ARG; + } + + memset(&arg, 0, sizeof(arg)); + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GATTC; + msg.act = BTC_GATTC_ACT_CANCEL_OPEN; + arg.cancel_open.gattc_if = params->gattc_if; + memcpy(arg.cancel_open.remote_bda, params->remote_bda, ESP_BD_ADDR_LEN); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gattc_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + esp_err_t esp_ble_gattc_send_mtu_req (esp_gatt_if_t gattc_if, uint16_t conn_id) { btc_msg_t msg = {0}; diff --git a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h index 1f00c59971..3426e33000 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h @@ -33,7 +33,7 @@ typedef enum { ESP_GATTC_PREP_WRITE_EVT = 11, /*!< This event is triggered upon the completion of a GATT prepare-write operation using `esp_ble_gattc_prepare_write`. */ ESP_GATTC_EXEC_EVT = 12, /*!< This event is triggered upon the completion of a GATT write execution using `esp_ble_gattc_execute_write` .*/ ESP_GATTC_ACL_EVT = 13, /*!< Deprecated. */ - ESP_GATTC_CANCEL_OPEN_EVT = 14, /*!< Deprecated. */ + ESP_GATTC_CANCEL_OPEN_EVT = 14, /*!< This event is triggered when a pending GATT connection open is cancelled via `esp_ble_gattc_cancel_open`. */ ESP_GATTC_SRVC_CHG_EVT = 15, /*!< This event is triggered when a service changed indication is received from the Server, indicating that the attribute database on the Server has been modified (e.g., services have been added, removed). */ ESP_GATTC_ENC_CMPL_CB_EVT = 17, /*!< Deprecated. */ ESP_GATTC_CFG_MTU_EVT = 18, /*!< This event is triggered upon the completion of the MTU configuration with `esp_ble_gattc_send_mtu_req`. */ @@ -256,6 +256,14 @@ typedef union { uint16_t conn_id; /*!< Connection ID */ } dis_srvc_cmpl; /*!< Callback parameter for the event `ESP_GATTC_DIS_SRVC_CMPL_EVT` */ + /** + * @brief Callback parameter for the event `ESP_GATTC_CANCEL_OPEN_EVT` + */ + struct gattc_cancel_open_evt_param { + esp_gatt_status_t status; /*!< Operation status */ + esp_bd_addr_t remote_bda; /*!< Remote device address that was cancelled */ + } cancel_open; /*!< Callback parameter for the event `ESP_GATTC_CANCEL_OPEN_EVT` */ + } esp_ble_gattc_cb_param_t; /** @@ -417,6 +425,34 @@ esp_err_t esp_ble_gattc_aux_open_with_pawr_synced(esp_gatt_if_t gattc_if, esp_bl */ esp_err_t esp_ble_gattc_close(esp_gatt_if_t gattc_if, uint16_t conn_id); +/** + * @brief Parameters for cancelling a pending GATT connection open + */ +typedef struct { + esp_gatt_if_t gattc_if; /*!< GATT client access interface */ + esp_bd_addr_t remote_bda; /*!< Remote device address to cancel */ +} esp_ble_gattc_cancel_open_params_t; + +/** + * @brief Cancel a pending GATT connection open + * + * Call this API to cancel a connection that was initiated by `esp_ble_gattc_enh_open` + * before it completes or times out. If the connection is already established, + * use `esp_ble_gap_disconnect` instead. + * + * @param[in] params Pointer to cancel open parameters (gattc_if, remote_bda) + * + * @note + * 1. This function triggers `ESP_GATTC_CANCEL_OPEN_EVT` on completion. + * 2. If no matching pending connection is found, the callback receives status `ESP_GATT_ERROR`. + * + * @return + * - ESP_OK: Request sent successfully + * - ESP_ERR_INVALID_ARG: Invalid argument (e.g. params is NULL or remote_bda is NULL) + * - ESP_FAIL: Bluedroid not enabled or transfer failed + */ +esp_err_t esp_ble_gattc_cancel_open(const esp_ble_gattc_cancel_open_params_t *params); + /** * @brief Configure the MTU size in the GATT channel * diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index e808dc9f54..c3406f6a93 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -392,8 +392,14 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_ p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if); if (p_clreg && p_clreg->p_cback) { - cb_data.status = BTA_GATT_ERROR; + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.cancel_open.status = BTA_GATT_ERROR; + cb_data.cancel_open.client_if = p_msg->api_cancel_conn.client_if; + bdcpy(cb_data.cancel_open.remote_bda, p_msg->api_cancel_conn.remote_bda); (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); + } else { + APPL_TRACE_ERROR("Cannot report cancel open result: client_if=%d not registered or no callback", + p_msg->api_cancel_conn.client_if); } } } else { @@ -443,7 +449,12 @@ void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_dat tBTA_GATTC cb_data; UNUSED(p_data); - cb_data.status = BTA_GATT_ERROR; + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.cancel_open.status = BTA_GATT_ERROR; + if (p_clcb && p_clcb->p_rcb) { + cb_data.cancel_open.client_if = p_clcb->p_rcb->client_if; + bdcpy(cb_data.cancel_open.remote_bda, p_clcb->bda); + } if ( p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback ) { (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); @@ -641,12 +652,16 @@ void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) { tBTA_GATTC_RCB *p_clreg; tBTA_GATTC cb_data; - cb_data.status = BTA_GATT_ERROR; + + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.cancel_open.status = BTA_GATT_ERROR; + cb_data.cancel_open.client_if = p_data->client_if; + bdcpy(cb_data.cancel_open.remote_bda, p_data->remote_bda); /* remove the device from the bg connection mask */ if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE, FALSE)) { if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE)) { - cb_data.status = BTA_GATT_OK; + cb_data.cancel_open.status = BTA_GATT_OK; } else { APPL_TRACE_ERROR("bta_gattc_cancel_bk_conn failed"); } @@ -673,7 +688,10 @@ void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) UNUSED(p_data); if ( p_clcb->p_rcb->p_cback ) { - cb_data.status = BTA_GATT_OK; + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.cancel_open.status = BTA_GATT_OK; + cb_data.cancel_open.client_if = p_clcb->p_rcb->client_if; + bdcpy(cb_data.cancel_open.remote_bda, p_clcb->bda); (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } @@ -696,7 +714,10 @@ void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data); } else { if ( p_clcb->p_rcb->p_cback ) { - cb_data.status = BTA_GATT_ERROR; + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.cancel_open.status = BTA_GATT_ERROR; + cb_data.cancel_open.client_if = p_clcb->p_rcb->client_if; + bdcpy(cb_data.cancel_open.remote_bda, p_clcb->bda); (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } } diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h index 7c2a4c154c..d18badf2d5 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h @@ -429,6 +429,12 @@ typedef struct { BD_ADDR remote_bda; } tBTA_GATTC_SERVICE_CHANGE; +typedef struct { + tBTA_GATT_STATUS status; + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; +} tBTA_GATTC_CANCEL_OPEN; + typedef union { tBTA_GATT_STATUS status; tBTA_GATTC_DIS_CMPL dis_cmpl; /* discovery complete */ @@ -450,6 +456,7 @@ typedef union { tBTA_GATTC_SERVICE_CHANGE srvc_chg; /* service change event */ tBTA_GATTC_SET_ASSOC set_assoc; tBTA_GATTC_GET_ADDR_LIST get_addr_list; + tBTA_GATTC_CANCEL_OPEN cancel_open; } tBTA_GATTC; /* GATTC enable callback function */ diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c index 9928a7ab2e..07e5fd1b82 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 @@ -232,10 +232,15 @@ static void btc_gattc_open(btc_ble_gattc_args_t *arg) static void btc_gattc_close(btc_ble_gattc_args_t *arg) { - // TODO; Review this call of BTA_API, check the usage of BTA_GATTC_CancelOpen BTA_GATTC_Close(arg->close.conn_id); } +static void btc_gattc_cancel_open(btc_ble_gattc_args_t *arg) +{ + /* ESP API path: always cancel as direct connection */ + BTA_GATTC_CancelOpen(arg->cancel_open.gattc_if, arg->cancel_open.remote_bda, TRUE); +} + static void btc_gattc_cfg_mtu(btc_ble_gattc_args_t *arg) { BTA_GATTC_ConfigureMTU (arg->cfg_mtu.conn_id); @@ -743,6 +748,9 @@ void btc_gattc_call_handler(btc_msg_t *msg) case BTC_GATTC_ACT_CLOSE: btc_gattc_close(arg); break; + case BTC_GATTC_ACT_CANCEL_OPEN: + btc_gattc_cancel_open(arg); + break; case BTC_GATTC_ACT_CFG_MTU: btc_gattc_cfg_mtu(arg); break; @@ -1006,7 +1014,12 @@ void btc_gattc_cb_handler(btc_msg_t *msg) break; } case BTA_GATTC_CANCEL_OPEN_EVT: { - /* Currently, this event will never happen */ + tBTA_GATTC_CANCEL_OPEN *cancel = &arg->cancel_open; + + gattc_if = cancel->client_if; + param.cancel_open.status = cancel->status; + memcpy(param.cancel_open.remote_bda, cancel->remote_bda, sizeof(esp_bd_addr_t)); + btc_gattc_cb_to_app(ESP_GATTC_CANCEL_OPEN_EVT, gattc_if, ¶m); break; } case BTA_GATTC_CONGEST_EVT: { diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h index 7580b7f17c..62af5a0f2d 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ typedef enum { BTC_GATTC_ACT_AUX_OPEN, #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) BTC_GATTC_ACT_CLOSE, + BTC_GATTC_ACT_CANCEL_OPEN, BTC_GATTC_ACT_CFG_MTU, BTC_GATTC_ACT_SEARCH_SERVICE, BTC_GATTC_ACT_READ_CHAR, @@ -70,6 +71,11 @@ typedef union { struct close_arg { uint16_t conn_id; } close; + //BTC_GATTC_ACT_CANCEL_OPEN, + struct cancel_open_arg { + esp_gatt_if_t gattc_if; + esp_bd_addr_t remote_bda; + } cancel_open; //BTC_GATTC_ACT_CFG_MTU, struct cfg_mtu_arg { uint16_t conn_id;