Merge branch 'bugfix/fix_hid_device_vup_without_connection' into 'master'

Bugfix/Fix HID Device can not remove virtually cabled device without a connection

Closes IDFGH-8662

See merge request espressif/esp-idf!21152
This commit is contained in:
Li Qi Gan 2022-12-12 10:08:57 +08:00
commit df5c1ffd8b
6 changed files with 137 additions and 64 deletions

View File

@ -259,123 +259,144 @@ typedef union {
} esp_hidd_cb_param_t;
/**
* @brief HID device callback function type.
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
* @brief HID device callback function type.
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (*esp_hd_cb_t)(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);
/**
* @brief This function is called to init callbacks with HID device module.
* @brief This function is called to init callbacks with HID device module.
*
* @param[in] callback: pointer to the init callback function.
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t callback);
/**
* @brief This function initializes HIDD. This function should be called after esp_bluedroid_enable and
* esp_bluedroid_init success, and should be called after esp_bt_hid_device_register_callback.
* When the operation is complete the callback function will be called with ESP_HIDD_INIT_EVT.
* @brief Initializes HIDD interface. This function should be called after esp_bluedroid_init() and
* esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_register_callback.
* When the operation is complete, the callback function will be called with ESP_HIDD_INIT_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_init(void);
/**
* @brief This function de-initializes HIDD interface. This function should be called after esp_bluedroid_enable() and
* esp_bluedroid_init() success, and should be called after esp_bt_hid_device_init(). When the operation is complete the callback
* function will be called with ESP_HIDD_DEINIT_EVT.
* @brief De-initializes HIDD interface. This function should be called after esp_bluedroid_init() and
* esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_init(). When the
* operation is complete, the callback function will be called with ESP_HIDD_DEINIT_EVT.
*
* @return - ESP_OK: success
* - other: failed
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_deinit(void);
/**
* @brief Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be called after
* esp_bluedroid_enable and esp_bluedroid_init success, and must be done after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_REGISTER_APP_EVT.
* @brief Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be
* called after esp_bluedroid_init() and esp_bluedroid_enable() success, and should be called after
* esp_bt_hid_device_init(). When the operation is complete, the callback function will be called
* with ESP_HIDD_REGISTER_APP_EVT.
*
* @param[in] app_param: HIDD parameters
* @param[in] in_qos: incoming QoS parameters
* @param[in] out_qos: outgoing QoS parameters
* @param[in] app_param: HIDD parameters
* @param[in] in_qos: incoming QoS parameters
* @param[in] out_qos: outgoing QoS parameters
*
* @return - ESP_OK: success
* - other: failed
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t *app_param, esp_hidd_qos_param_t *in_qos,
esp_hidd_qos_param_t *out_qos);
/**
* @brief Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be called after esp_bluedroid_enable and
* esp_bluedroid_init success, and should be called after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_UNREGISTER_APP_EVT.
* @brief Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be
* called after esp_bluedroid_init() and esp_bluedroid_enable() success, and should be called after
* esp_bt_hid_device_init(). When the operation is complete, the callback function will be called
* with ESP_HIDD_UNREGISTER_APP_EVT.
*
* @return - ESP_OK: success
* - other: failed
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_unregister_app(void);
/**
* @brief This function connects HIDD interface to connected bluetooth device, if not done already. When the operation is complete the callback
* function will be called with ESP_HIDD_OPEN_EVT.
* @brief Connects to the peer HID Host with virtual cable. This function should be called after
* esp_bluedroid_init() and esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_init().
* When the operation is complete, the callback function will be called with ESP_HIDD_OPEN_EVT.
*
* @param[in] bd_addr: Remote host bluetooth device address.
* @param[in] bd_addr: Remote host bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr);
/**
* @brief This function disconnects HIDD interface. When the operation is complete the callback
* function will be called with ESP_HIDD_CLOSE_EVT.
* @brief Disconnects from the currently connected HID Host. This function should be called after
* esp_bluedroid_init() and esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_init().
* When the operation is complete, the callback function will be called with ESP_HIDD_CLOSE_EVT.
*
* @note The disconnect operation will not remove the virtually cabled device. If the connect request from the
* different HID Host, it will reject the request.
*
* @return
* - ESP_OK: success
* - other: failed
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_disconnect(void);
/**
* @brief Send HIDD report. When the operation is complete the callback
* function will be called with ESP_HIDD_SEND_REPORT_EVT.
* @brief Sends HID report to the currently connected HID Host. This function should be called after
* esp_bluedroid_init() and esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_init().
* When the operation is complete, the callback function will be called with ESP_HIDD_SEND_REPORT_EVT.
*
* @param[in] type: type of report
* @param[in] id: report id as defined by descriptor
* @param[in] len: length of report
* @param[in] data: report data
* @param[in] type: type of report
* @param[in] id: report id as defined by descriptor
* @param[in] len: length of report
* @param[in] data: report data
*
* @return
* - ESP_OK: success
* - other: failed
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *data);
/**
* @brief Sends HIDD handshake with error info for invalid set_report. When the operation is complete the callback
* function will be called with ESP_HIDD_REPORT_ERR_EVT.
* @brief Sends HID Handshake with error info for invalid set_report to the currently connected HID Host.
* This function should be called after esp_bluedroid_init() and esp_bluedroid_enable() success, and
* should be called after esp_bt_hid_device_init(). When the operation is complete, the callback
* function will be called with ESP_HIDD_REPORT_ERR_EVT.
*
* @param[in] error: type of error
* @param[in] error: type of error
*
* @return - ESP_OK: success
* - other: failed
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error);
/**
* @brief Unplug virtual cable of HIDD. When the operation is complete the callback
* function will be called with ESP_HIDD_VC_UNPLUG_EVT.
* @brief Remove the virtually cabled device. This function should be called after esp_bluedroid_init()
* and esp_bluedroid_enable() success, and should be called after esp_bt_hid_device_init(). When the
* operation is complete, the callback function will be called with ESP_HIDD_VC_UNPLUG_EVT.
*
* @return - ESP_OK: success
* - other: failed
* @note If the connection exists, then HID Device will send a `VIRTUAL_CABLE_UNPLUG` control command to
* the peer HID Host, and the connection will be destroyed. If the connection does not exist, then HID
* Device will only unplug on it's single side. Once the unplug operation is success, the related
* pairing and bonding information will be removed, then the HID Device can accept connection request
* from the different HID Host,
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void);

View File

@ -422,13 +422,28 @@ extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data)
extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
tBTA_HD cback_data = {0};
BD_ADDR plugged_addr = {0};
APPL_TRACE_API("%s", __func__);
bta_hd_cb.vc_unplug = TRUE;
ret = HID_DevVirtualCableUnplug();
if (ret != HID_SUCCESS) {
if (ret == HID_ERR_NO_CONNECTION) {
/* This is a local VUP without connection, set the vc_unplug to FALSE */
bta_hd_cb.vc_unplug = FALSE;
APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret);
if (HID_DevGetDevice(&plugged_addr) == HID_SUCCESS) {
HID_DevUnplugDevice(plugged_addr);
}
APPL_TRACE_DEBUG("%s local VUP, remove bda: %02x:%02x:%02x:%02x:%02x:%02x", __func__, plugged_addr[0],
plugged_addr[1], plugged_addr[2], plugged_addr[3], plugged_addr[4], plugged_addr[5]);
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
bta_hd_cb.p_cback(BTA_HD_VC_UNPLUG_EVT, &cback_data);
return;
} else if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret);
}

View File

@ -116,7 +116,7 @@ const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},

View File

@ -254,6 +254,12 @@ static void btc_hd_deinit(void)
break;
}
if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_ERROR("%s is disabling, try later!", __func__);
ret = ESP_HIDD_BUSY;
break;
}
btc_hd_cb.service_dereg_active = FALSE;
btc_hd_cb.status = BTC_HD_DISABLING;
// unresgister app will also relase the connection
@ -411,6 +417,13 @@ static void btc_hd_connect(BD_ADDR bd_addr)
ret = ESP_HIDD_NEED_REG;
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);
} while (0);
@ -448,6 +461,13 @@ static void btc_hd_disconnect(void)
ret = ESP_HIDD_NEED_REG;
break;
}
if (btc_hd_cb.status != BTC_HD_CONNECTED) {
BTC_TRACE_ERROR("%s: already disconnected!", __func__);
ret = ESP_HIDD_NO_CONNECTION;
break;
}
BTA_HdDisconnect();
} while (0);
@ -721,6 +741,7 @@ void btc_hd_cb_handler(btc_msg_t *msg)
// break;
// }
// btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda);
btc_hd_cb.status = BTC_HD_CONNECTED;
}
param.open.status = p_data->conn.status;
param.open.conn_status = p_data->conn.conn_status;
@ -736,6 +757,11 @@ void btc_hd_cb_handler(btc_msg_t *msg)
btc_hd_cb.forced_disc = FALSE;
break;
}
if (btc_hd_cb.status == BTC_HD_CONNECTED) {
btc_hd_cb.status = BTC_HD_ENABLED;
}
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, &param);
@ -782,9 +808,14 @@ void btc_hd_cb_handler(btc_msg_t *msg)
BTC_TRACE_DEBUG("%s: Only removing HID data as some other profiles connected", __func__);
btc_hd_remove_device(*bd_addr);
}
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, &param);
if (btc_hd_cb.status == BTC_HD_CONNECTED) {
btc_hd_cb.status = BTC_HD_ENABLED;
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, &param);
}
param.vc_unplug.status = p_data->conn.status;
param.vc_unplug.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);

View File

@ -39,7 +39,7 @@ typedef enum {
BTC_HD_UNPLUG_EVT,
} BTC_HD_EVT;
typedef enum { BTC_HD_DISABLED = 0, BTC_HD_ENABLED, BTC_HD_DISABLING } BTC_HD_STATUS;
typedef enum { BTC_HD_DISABLED = 0, BTC_HD_ENABLED, BTC_HD_CONNECTED, BTC_HD_DISABLING } BTC_HD_STATUS;
/* BTIF-HD control block */
typedef struct {

View File

@ -312,8 +312,14 @@ void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
}
break;
case ESP_HIDD_SEND_REPORT_EVT:
ESP_LOGI(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d", param->send_report.report_id,
param->send_report.report_type);
if (param->send_report.status == ESP_HIDD_SUCCESS) {
ESP_LOGI(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d", param->send_report.report_id,
param->send_report.report_type);
} else {
ESP_LOGE(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d, status:%d, reason:%d",
param->send_report.report_id, param->send_report.report_type, param->send_report.status,
param->send_report.reason);
}
break;
case ESP_HIDD_REPORT_ERR_EVT:
ESP_LOGI(TAG, "ESP_HIDD_REPORT_ERR_EVT");