diff --git a/components/bt/host/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c index e0be0df81d..25c6357924 100644 --- a/components/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -1599,3 +1599,31 @@ esp_err_t esp_ble_gap_set_periodic_adv_sync_trans_params(esp_bd_addr_t addr, con == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } #endif //#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) + +esp_err_t esp_ble_gap_vendor_command_send(esp_ble_vendor_cmd_params_t *vendor_cmd_param) +{ + btc_msg_t msg = {0}; + btc_ble_gap_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (!vendor_cmd_param || !vendor_cmd_param->p_param_buf || !vendor_cmd_param->param_len) { + return ESP_ERR_INVALID_ARG; + } + // If command is not a VSC, return error + if ((vendor_cmd_param->opcode & VENDOR_HCI_CMD_MASK) != VENDOR_HCI_CMD_MASK) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT; + arg.vendor_cmd_send.opcode = vendor_cmd_param->opcode; + arg.vendor_cmd_send.param_len = vendor_cmd_param->param_len; + arg.vendor_cmd_send.p_param_buf = vendor_cmd_param->p_param_buf; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy, btc_gap_ble_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h index 8665938bc9..e61f3fe431 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -224,6 +224,7 @@ typedef enum { ESP_GAP_BLE_DTM_TEST_UPDATE_EVT, /*!< when direct test mode state changes, the event comes */ // BLE_INCLUDED ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT, /*!< When clear advertising complete, the event comes */ + ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT, /*!< When vendor hci command complete, the event comes */ ESP_GAP_BLE_EVT_MAX, /*!< when maximum advertising event complete, the event comes */ } esp_gap_ble_cb_event_t; @@ -238,6 +239,8 @@ typedef uint8_t esp_gap_ble_channels[ESP_GAP_BLE_CHANNELS_LEN]; /// Scan response data maximum length #define ESP_BLE_SCAN_RSP_DATA_LEN_MAX 31 +#define VENDOR_HCI_CMD_MASK (0x3F << 10) /**!< 0xFC00 */ + /* relate to BTM_BLE_AD_TYPE_xxx in stack/btm_ble_api.h */ /// The type of advertising data(not adv_type) typedef enum { @@ -364,6 +367,15 @@ typedef enum { DTM_TEST_STOP_EVT, } esp_ble_dtm_update_evt_t; +/** + * @brief Vendor HCI command parameters + */ +typedef struct { + uint16_t opcode; /*!< vendor hci command opcode */ + uint8_t param_len; /*!< the length of parameter */ + uint8_t *p_param_buf; /*!< the point of parameter buffer */ +} esp_ble_vendor_cmd_params_t; + #if (BLE_42_FEATURE_SUPPORT == TRUE) /** * @brief DTM TX parameters @@ -1462,6 +1474,14 @@ typedef union { esp_ble_dtm_update_evt_t update_evt; /*!< DTM state change event, 0x00: DTM TX start, 0x01: DTM RX start, 0x02:DTM end */ uint16_t num_of_pkt; /*!< number of packets received, only valid if update_evt is DTM_TEST_STOP_EVT and shall be reported as 0 for a transmitter */ } dtm_state_update; /*!< Event parameter of ESP_GAP_BLE_DTM_TEST_UPDATE_EVT */ + /** + * @brief ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT + */ + struct vendor_cmd_cmpl_evt_param { + uint16_t opcode; /*!< vendor hci command opcode */ + uint16_t param_len; /*!< The length of parameter buffer */ + uint8_t *p_param_buf; /*!< The point of parameter buffer */ + } vendor_cmd_cmpl; /*!< Event parameter of ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT */ } esp_ble_gap_cb_param_t; /** @@ -2531,6 +2551,19 @@ esp_err_t esp_ble_dtm_stop(void); */ esp_err_t esp_ble_gap_clear_advertising(void); +/** + * @brief This function is called to send vendor hci command. + * + * + * + * @param[in] vendor_cmd_param: vendor hci command parameters + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_vendor_command_send(esp_ble_vendor_cmd_params_t *vendor_cmd_param); + #ifdef __cplusplus } #endif diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index c83b7607ec..96ba83efaf 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -707,6 +707,14 @@ void bta_dm_get_dev_name (tBTA_DM_MSG *p_data) } } +void bta_dm_send_vendor_hci(tBTA_DM_MSG *p_data) +{ + BTM_VendorSpecificCommand(p_data->vendor_hci_cmd.opcode, + p_data->vendor_hci_cmd.param_len, + p_data->vendor_hci_cmd.p_param_buf, + p_data->vendor_hci_cmd.vendor_hci_cb); +} + /******************************************************************************* ** ** Function bta_dm_set_afh_channels diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c index f65bc4dd6f..79104caac1 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c @@ -202,6 +202,21 @@ void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback) } } +void BTA_DmsendVendorHciCmd(UINT16 opcode, UINT8 param_len, UINT8 *p_param_buf, tBTA_SEND_VENDOR_HCI_CMPL_CBACK p_vendor_cmd_complete_cback) +{ + tBTA_DM_API_SEND_VENDOR_HCI_CMD *p_msg; + if ((p_msg = (tBTA_DM_API_SEND_VENDOR_HCI_CMD *)osi_malloc(sizeof(tBTA_DM_API_SEND_VENDOR_HCI_CMD) + param_len)) != NULL) { + p_msg->hdr.event = BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT; + p_msg->opcode = opcode; + p_msg->param_len = param_len; + p_msg->p_param_buf = (UINT8 *)(p_msg + 1); + memcpy(p_msg->p_param_buf, p_param_buf, param_len); + p_msg->vendor_hci_cb = p_vendor_cmd_complete_cback; + + bta_sys_sendmsg(p_msg); + } +} + #if (CLASSIC_BT_INCLUDED == TRUE) void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config) diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c index 1190743079..38d9017324 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c @@ -58,6 +58,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_disable, /* BTA_DM_API_DISABLE_EVT */ bta_dm_set_dev_name, /* BTA_DM_API_SET_NAME_EVT */ bta_dm_get_dev_name, /* BTA_DM_API_GET_NAME_EVT */ + bta_dm_send_vendor_hci, /* BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT */ #if (CLASSIC_BT_INCLUDED == TRUE) bta_dm_config_eir, /* BTA_DM_API_CONFIG_EIR_EVT */ #endif diff --git a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index 30a42427c3..0fac1e934d 100644 --- a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -54,6 +54,7 @@ enum { BTA_DM_API_DISABLE_EVT, BTA_DM_API_SET_NAME_EVT, BTA_DM_API_GET_NAME_EVT, + BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT, #if (CLASSIC_BT_INCLUDED == TRUE) BTA_DM_API_CONFIG_EIR_EVT, #endif @@ -250,6 +251,14 @@ typedef struct { tBTA_GET_DEV_NAME_CBACK *p_cback; } tBTA_DM_API_GET_NAME; +typedef struct { + BT_HDR hdr; + UINT16 opcode; + UINT8 param_len; + UINT8 *p_param_buf; + tBTA_SEND_VENDOR_HCI_CMPL_CBACK *vendor_hci_cb; +}tBTA_DM_API_SEND_VENDOR_HCI_CMD; + /* data type for BTA_DM_API_CONFIG_EIR_EVT */ typedef struct { BT_HDR hdr; @@ -1122,6 +1131,7 @@ typedef union { tBTA_DM_API_SET_NAME set_name; tBTA_DM_API_GET_NAME get_name; + tBTA_DM_API_SEND_VENDOR_HCI_CMD vendor_hci_cmd; tBTA_DM_API_CONFIG_EIR config_eir; tBTA_DM_API_SET_AFH_CHANNELS set_afh_channels; @@ -1630,6 +1640,7 @@ extern void bta_dm_enable (tBTA_DM_MSG *p_data); extern void bta_dm_disable (tBTA_DM_MSG *p_data); extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data); extern void bta_dm_get_dev_name (tBTA_DM_MSG *p_data); +extern void bta_dm_send_vendor_hci(tBTA_DM_MSG *p_data); #if (CLASSIC_BT_INCLUDED == TRUE) extern void bta_dm_config_eir (tBTA_DM_MSG *p_data); #endif diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_api.h index 2f65ecce30..163ec270f3 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_api.h @@ -416,6 +416,8 @@ typedef void (tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTA_STATUS st typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status); +typedef tBTM_VSC_CMPL_CB tBTA_SEND_VENDOR_HCI_CMPL_CBACK; + typedef tBTM_START_ADV_CMPL_CBACK tBTA_START_ADV_CMPL_CBACK; typedef tBTM_START_STOP_ADV_CMPL_CBACK tBTA_START_STOP_ADV_CMPL_CBACK; @@ -432,6 +434,8 @@ typedef tBTM_SET_LOCAL_PRIVACY_CBACK tBTA_SET_LOCAL_PRIVACY_CBACK; typedef tBTM_CMPL_CB tBTA_CMPL_CB; +typedef tBTM_VSC_CMPL tBTA_VSC_CMPL; + typedef tBTM_TX_POWER_RESULTS tBTA_TX_POWER_RESULTS; typedef tBTM_RSSI_RESULTS tBTA_RSSI_RESULTS; @@ -1713,6 +1717,8 @@ extern void BTA_DmSetDeviceName(const char *p_name); *******************************************************************************/ extern void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback); +extern void BTA_DmsendVendorHciCmd(UINT16 opcode, UINT8 param_len, UINT8 *p_param_buf, tBTA_SEND_VENDOR_HCI_CMPL_CBACK p_vendor_cmd_complete_cback); + /******************************************************************************* ** ** Function BTA_DmGetRemoteName diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 0075f483b6..9cf2949b80 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -1249,6 +1249,42 @@ void btc_dtm_stop_callback(void *p1) } } +static void btc_ble_vendor_hci_cmd_complete_callback(tBTA_VSC_CMPL *p_param) +{ + bool param_invalid = false; + if ((!p_param) || (!p_param->param_len) || (!p_param->p_param_buf)) { + BTC_TRACE_ERROR("%s param error\n", __func__); + param_invalid = true; + } + + esp_ble_gap_cb_param_t param = {0}; + bt_status_t ret; + btc_msg_t msg = {0}; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT; + if (!param_invalid) { + param.vendor_cmd_cmpl.opcode = p_param->opcode; + param.vendor_cmd_cmpl.param_len = p_param->param_len; + param.vendor_cmd_cmpl.p_param_buf = p_param->p_param_buf; + } else { + if (p_param) { + param.vendor_cmd_cmpl.opcode = p_param->opcode; + } else { + param.vendor_cmd_cmpl.opcode = 0; + } + param.vendor_cmd_cmpl.param_len = 0; + param.vendor_cmd_cmpl.p_param_buf = NULL; + } + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), btc_gap_ble_cb_deep_copy, btc_gap_ble_cb_deep_free); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + void btc_get_whitelist_size(uint16_t *length) { BTM_BleGetWhiteListSize(length); @@ -1591,6 +1627,19 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) break; } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: { + btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src; + btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *)p_dest; + if (src->vendor_cmd_send.param_len) { + dst->vendor_cmd_send.p_param_buf = osi_malloc(src->vendor_cmd_send.param_len); + if (dst->vendor_cmd_send.p_param_buf) { + memcpy(dst->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.param_len); + } else { + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + } + break; + } default: BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act); break; @@ -1599,7 +1648,22 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { + esp_ble_gap_cb_param_t *src = (esp_ble_gap_cb_param_t *)p_src; + esp_ble_gap_cb_param_t *dst = (esp_ble_gap_cb_param_t *) p_dest; + switch (msg->act) { + case ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT: { + if (src->vendor_cmd_cmpl.param_len) { + dst->vendor_cmd_cmpl.p_param_buf = osi_malloc(src->vendor_cmd_cmpl.param_len); + if (dst->vendor_cmd_cmpl.p_param_buf) { + memcpy(dst->vendor_cmd_cmpl.p_param_buf, src->vendor_cmd_cmpl.p_param_buf, + src->vendor_cmd_cmpl.param_len); + } else { + BTC_TRACE_ERROR("%s, malloc failed\n", __func__); + } + } + break; + } default: BTC_TRACE_ERROR("%s, Unhandled deep copy %d\n", __func__, msg->act); break; @@ -1697,6 +1761,13 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg) break; } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: { + uint8_t *p_param_buf = ((btc_ble_gap_args_t *)msg->arg)->vendor_cmd_send.p_param_buf; + if (p_param_buf) { + osi_free(p_param_buf); + } + break; + } default: BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act); break; @@ -1714,6 +1785,13 @@ void btc_gap_ble_cb_deep_free(btc_msg_t *msg) } break; } + case ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT: { + uint8_t *value = ((esp_ble_gap_cb_param_t *)msg->arg)->vendor_cmd_cmpl.p_param_buf; + if (value) { + osi_free(value); + } + break; + } default: BTC_TRACE_DEBUG("Unhandled deep free %d", msg->act); break; @@ -2181,6 +2259,12 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_dtm_enhance_rx_start(arg_5->dtm_enh_rx_start.rx_channel, arg_5->dtm_enh_rx_start.phy, arg_5->dtm_enh_rx_start.modulation_index, btc_dtm_rx_start_callback); break; #endif // if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: + BTA_DmsendVendorHciCmd(arg->vendor_cmd_send.opcode, + arg->vendor_cmd_send.param_len, + arg->vendor_cmd_send.p_param_buf, + btc_ble_vendor_hci_cmd_complete_callback); + break; default: break; } diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h index a427be142c..71d89359d9 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -102,6 +102,7 @@ typedef enum { #if (BLE_42_FEATURE_SUPPORT == TRUE) BTC_GAP_BLE_ACT_CLEAR_ADV, #endif // #if (BLE_42_FEATURE_SUPPORT == TRUE) + BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT, } btc_gap_ble_act_t; /* btc_ble_gap_args_t */ @@ -248,6 +249,12 @@ typedef union { struct dtm_rx_start_args { uint8_t rx_channel; } dtm_rx_start; + //BTC_DEV_VENDOR_HCI_CMD_EVT + struct vendor_cmd_send_args { + uint16_t opcode; + uint8_t param_len; + uint8_t *p_param_buf; + } vendor_cmd_send; } btc_ble_gap_args_t; #if (BLE_50_FEATURE_SUPPORT == TRUE) diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 31d7d15287..7f837ed358 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -723,8 +723,9 @@ void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, break; } default: - break; + break; } +#endif // (BLE_INCLUDED == TRUE) tBTM_VSC_CMPL vcs_cplt_params; /* If there was a callback address for vcs complete, call it */ @@ -735,7 +736,7 @@ void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, vcs_cplt_params.p_param_buf = p; (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */ } -#endif + } /*******************************************************************************