From 1963f75fa7f60021d253cbc807e8aeaab73fcde8 Mon Sep 17 00:00:00 2001 From: liqigan Date: Mon, 4 Sep 2023 16:30:47 +0800 Subject: [PATCH] change(bt/bluedroid): Optimize HIDD sending interrupt report behavior HID device is allowed to trigger reconnection by sending an interrupt report. When reconnection is in progress, no more interrupt report can be sent until the procedure is accomplished. --- .../bluedroid/btc/profile/std/hid/btc_hd.c | 190 ++++++++++++++---- .../btc/profile/std/include/btc_hd.h | 10 +- .../bt/host/bluedroid/stack/hid/hidd_conn.c | 8 +- 3 files changed, 161 insertions(+), 47 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c index 202f90b0a4..d280f8f7eb 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c @@ -52,7 +52,7 @@ typedef enum { BTC_HD_DUMMY_REQ_EVT = 0 } btc_hd_req_evt_t; /******************************************************************************* * Static variables ******************************************************************************/ -btc_hd_cb_t btc_hd_cb; +btc_hd_cb_t btc_hd_cb = {0}; // static tBTA_HD_APP_INFO app_info; // static tBTA_HD_QOS_INFO in_qos; @@ -242,7 +242,7 @@ static void btc_hd_init(void) * Returns void * ******************************************************************************/ -static void btc_hd_unregister_app(void); +static void btc_hd_unregister_app(bool need_deinit); static void btc_hd_deinit(void) { BTC_TRACE_API("%s", __func__); @@ -261,12 +261,12 @@ static void btc_hd_deinit(void) } btc_hd_cb.service_dereg_active = FALSE; - btc_hd_cb.status = BTC_HD_DISABLING; // unresgister app will also relase the connection // and disable after receiving unregister event from lower layer if (is_hidd_app_register()) { - btc_hd_unregister_app(); + btc_hd_unregister_app(true); } else { + btc_hd_cb.status = BTC_HD_DISABLING; BTC_TRACE_WARNING("%s disabling hid device service now", __func__); BTA_HdDisable(); } @@ -298,6 +298,10 @@ static void btc_hd_register_app(esp_hidd_app_param_t *p_app_param, esp_hidd_qos_ BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + } else if (btc_hd_cb.status == BTC_HD_DISABLING) { + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; } if (is_hidd_app_register()) { @@ -359,7 +363,7 @@ static void btc_hd_register_app(esp_hidd_app_param_t *p_app_param, esp_hidd_qos_ * Returns void * ******************************************************************************/ -static void btc_hd_unregister_app(void) +static void btc_hd_unregister_app(bool need_deinit) { BTC_TRACE_API("%s", __func__); esp_hidd_status_t ret = ESP_HIDD_SUCCESS; @@ -368,6 +372,10 @@ static void btc_hd_unregister_app(void) BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + } else if (btc_hd_cb.status == BTC_HD_DISABLING) { + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; } if (!is_hidd_app_register()) { @@ -382,11 +390,16 @@ static void btc_hd_unregister_app(void) break; } btc_hd_cb.service_dereg_active = TRUE; + + if (need_deinit) { + btc_hd_cb.status = BTC_HD_DISABLING; + } + BTA_HdUnregisterApp(); } while(0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; + esp_hidd_cb_param_t param = {0}; param.unregister_app.status = ret; btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, ¶m); } @@ -405,11 +418,32 @@ static void btc_hd_connect(BD_ADDR bd_addr) { BTC_TRACE_API("%s", __func__); esp_hidd_status_t ret = ESP_HIDD_SUCCESS; + do { - if (!is_hidd_init()) { + switch (btc_hd_cb.status) { + case BTC_HD_DISABLED: BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + case BTC_HD_DISABLING: + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_CONNECTING: + case BTC_HD_DISCONNECTING: + BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_CONNECTED: + BTC_TRACE_ERROR("%s: already connect to the other HID host!", __func__); + ret = ESP_HIDD_NO_RES; + break; + default: + break; + } + + if (ret != ESP_HIDD_SUCCESS) { + break; } if (!is_hidd_app_register()) { @@ -418,17 +452,12 @@ static void btc_hd_connect(BD_ADDR bd_addr) break; } - if (btc_hd_cb.status == BTC_HD_CONNECTED) { - BTC_TRACE_ERROR("%s: already connect to the other HID host!", __func__); - ret = ESP_HIDD_NO_RES; - break; - } - BTA_HdConnect(bd_addr); + btc_hd_cb.status = BTC_HD_CONNECTING; } while (0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; + esp_hidd_cb_param_t param = {0}; param.open.status = ret; param.open.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED; memcpy(param.open.bd_addr, bd_addr, BD_ADDR_LEN); @@ -449,11 +478,33 @@ static void btc_hd_disconnect(void) { BTC_TRACE_API("%s", __func__); esp_hidd_status_t ret = ESP_HIDD_SUCCESS; + do { - if (!is_hidd_init()) { + switch (btc_hd_cb.status) { + case BTC_HD_DISABLED: BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + case BTC_HD_DISABLING: + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_CONNECTING: + case BTC_HD_DISCONNECTING: + BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_ENABLED: + case BTC_HD_DISCONNECTED: + BTC_TRACE_ERROR("%s: no connection!", __func__); + ret = ESP_HIDD_NO_CONNECTION; + break; + default: + break; + } + + if (ret != ESP_HIDD_SUCCESS) { + break; } if (!is_hidd_app_register()) { @@ -462,17 +513,12 @@ static void btc_hd_disconnect(void) break; } - if (btc_hd_cb.status != BTC_HD_CONNECTED) { - BTC_TRACE_ERROR("%s: already disconnected!", __func__); - ret = ESP_HIDD_NO_CONNECTION; - break; - } - BTA_HdDisconnect(); + btc_hd_cb.status = BTC_HD_DISCONNECTING; } while (0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; + esp_hidd_cb_param_t param = {0}; param.close.status = ret; param.close.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED; btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, ¶m); @@ -490,15 +536,41 @@ static void btc_hd_disconnect(void) ******************************************************************************/ static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *p_data) { - tBTA_HD_REPORT report; - BTC_TRACE_API("%s: type=%d id=%d len=%d", __func__, type, id, len); + tBTA_HD_REPORT report = {0}; esp_hidd_status_t ret = ESP_HIDD_SUCCESS; + do { - if (!is_hidd_init()) { + switch (btc_hd_cb.status) { + case BTC_HD_DISABLED: BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + case BTC_HD_DISABLING: + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_CONNECTING: + case BTC_HD_DISCONNECTING: + BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_ENABLED: + case BTC_HD_DISCONNECTED: + if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) { + BTC_TRACE_WARNING("%s: no connection, try to reconnect!", __func__); + btc_hd_cb.status = BTC_HD_CONNECTING; + } else { + BTC_TRACE_ERROR("%s: no connection!", __func__); + ret = ESP_HIDD_NO_CONNECTION; + } + break; + default: + break; + } + + if (ret != ESP_HIDD_SUCCESS) { + break; } if (!is_hidd_app_register()) { @@ -506,6 +578,7 @@ static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t ret = ESP_HIDD_NEED_REG; break; } + if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) { report.type = ESP_HIDD_REPORT_TYPE_INPUT; report.use_intr = TRUE; @@ -522,7 +595,7 @@ static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t } while (0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; + esp_hidd_cb_param_t param = {0}; param.send_report.status = ret; param.send_report.reason = 0; param.send_report.report_type = report.type; @@ -556,11 +629,18 @@ static void btc_hd_report_error(uint8_t error) ret = ESP_HIDD_NEED_REG; break; } + + if (btc_hd_cb.status != BTC_HD_CONNECTED) { + BTC_TRACE_ERROR("%s: no connection!", __func__); + ret = ESP_HIDD_NO_CONNECTION; + break; + } + BTA_HdReportError(error); } while (0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; + esp_hidd_cb_param_t param = {0}; param.report_err.status = ret; param.report_err.reason = 0; btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, ¶m); @@ -580,11 +660,28 @@ static void btc_hd_virtual_cable_unplug(void) { BTC_TRACE_API("%s", __func__); esp_hidd_status_t ret = ESP_HIDD_SUCCESS; + do { - if (!is_hidd_init()) { + switch (btc_hd_cb.status) { + case BTC_HD_DISABLED: BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__); ret = ESP_HIDD_NEED_INIT; break; + case BTC_HD_DISABLING: + BTC_TRACE_ERROR("%s: deinit is in progress!", __func__); + ret = ESP_HIDD_BUSY; + break; + case BTC_HD_CONNECTING: + case BTC_HD_DISCONNECTING: + BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status); + ret = ESP_HIDD_BUSY; + break; + default: + break; + } + + if (ret != ESP_HIDD_SUCCESS) { + break; } if (!is_hidd_app_register()) { @@ -592,13 +689,18 @@ static void btc_hd_virtual_cable_unplug(void) ret = ESP_HIDD_NEED_REG; break; } + BTA_HdVirtualCableUnplug(); + + if (btc_hd_cb.status == BTC_HD_CONNECTED) { + btc_hd_cb.status = BTC_HD_DISCONNECTING; + } } while (0); if (ret != ESP_HIDD_SUCCESS) { - esp_hidd_cb_param_t param; - param.report_err.status = ret; - param.report_err.reason = 0; + esp_hidd_cb_param_t param = {0}; + param.vc_unplug.status = ret; + param.vc_unplug.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED; btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, ¶m); } } @@ -630,7 +732,7 @@ void btc_hd_call_handler(btc_msg_t *msg) btc_hd_register_app(arg->register_app.app_param, arg->register_app.in_qos, arg->register_app.out_qos); break; case BTC_HD_UNREGISTER_APP_EVT: - btc_hd_unregister_app(); + btc_hd_unregister_app(false); break; case BTC_HD_CONNECT_EVT: btc_hd_connect(arg->connect.bd_addr); @@ -750,16 +852,15 @@ void btc_hd_cb_handler(btc_msg_t *msg) break; } case BTA_HD_CLOSE_EVT: - if (btc_hd_cb.forced_disc && p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) { - bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda; - BTC_TRACE_WARNING("remote device was forcefully disconnected"); - btc_hd_remove_device(*addr); - btc_hd_cb.forced_disc = FALSE; - break; - } - - if (btc_hd_cb.status == BTC_HD_CONNECTED) { - btc_hd_cb.status = BTC_HD_ENABLED; + if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) { + btc_hd_cb.status = BTC_HD_DISCONNECTED; + if (btc_hd_cb.forced_disc) { + bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda; + BTC_TRACE_WARNING("remote device was forcefully disconnected"); + btc_hd_remove_device(*addr); + btc_hd_cb.forced_disc = FALSE; + break; + } } param.close.status = p_data->conn.status; @@ -809,8 +910,9 @@ void btc_hd_cb_handler(btc_msg_t *msg) btc_hd_remove_device(*bd_addr); } - if (btc_hd_cb.status == BTC_HD_CONNECTED) { - btc_hd_cb.status = BTC_HD_ENABLED; + if (btc_hd_cb.status == BTC_HD_DISCONNECTING || btc_hd_cb.status == BTC_HD_CONNECTING || + btc_hd_cb.status == BTC_HD_CONNECTED) { + btc_hd_cb.status = BTC_HD_DISCONNECTED; param.close.status = p_data->conn.status; param.close.conn_status = p_data->conn.conn_status; btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, ¶m); diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_hd.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_hd.h index 7fe7460c10..c290dd7c0a 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_hd.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_hd.h @@ -39,7 +39,15 @@ typedef enum { BTC_HD_UNPLUG_EVT, } BTC_HD_EVT; -typedef enum { BTC_HD_DISABLED = 0, BTC_HD_ENABLED, BTC_HD_CONNECTED, BTC_HD_DISABLING } BTC_HD_STATUS; +typedef enum { + BTC_HD_DISABLED = 0, + BTC_HD_ENABLED, + BTC_HD_DISABLING, + BTC_HD_CONNECTING, + BTC_HD_CONNECTED, + BTC_HD_DISCONNECTING, + BTC_HD_DISCONNECTED, +} BTC_HD_STATUS; /* BTIF-HD control block */ typedef struct { diff --git a/components/bt/host/bluedroid/stack/hid/hidd_conn.c b/components/bt/host/bluedroid/stack/hid/hidd_conn.c index 05a14799e0..623f085985 100644 --- a/components/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -709,11 +709,14 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param uint8_t *p_out; uint16_t cid; uint16_t buf_size; + HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len); + p_hcon = &hd_cb.device.conn; if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) { return HID_ERR_CONGESTED; } + switch (msg_type) { case HID_TRANS_HANDSHAKE: case HID_TRANS_CONTROL: @@ -760,7 +763,8 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param } hd_cb.pending_data = p_buf; if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) { - hidd_conn_initiate(); + HIDD_TRACE_WARNING("%s: try to reconnect!", __func__); + return hidd_conn_initiate(); } return HID_SUCCESS; } @@ -772,7 +776,7 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param } #endif HIDD_TRACE_VERBOSE("%s: report sent", __func__); - if (!L2CA_DataWrite(cid, p_buf)) + if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED || !L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED); return (HID_SUCCESS); }