/* * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "common/bt_target.h" #include #include "esp_bt_main.h" #include "esp_gap_bt_api.h" #include "esp_log.h" #include "common/bt_trace.h" #include "bta/bta_api.h" #include "btc/btc_manage.h" #include "btc_gap_bt.h" #include "btc/btc_storage.h" #include "config/stack_config.h" #if (BTC_GAP_BT_INCLUDED == TRUE) #define TAG "BT_GAP" esp_err_t esp_bt_gap_register_callback(esp_bt_gap_cb_t callback) { if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (callback == NULL) { return ESP_FAIL; } btc_profile_cb_set(BTC_PID_GAP_BT, callback); return ESP_OK; } esp_err_t esp_bt_gap_set_scan_mode(esp_bt_connection_mode_t c_mode, esp_bt_discovery_mode_t d_mode) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_SCAN_MODE; arg.set_scan_mode.c_mode = c_mode; arg.set_scan_mode.d_mode = d_mode; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, uint8_t num_rsps) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (mode != ESP_BT_INQ_MODE_GENERAL_INQUIRY && mode != ESP_BT_INQ_MODE_LIMITED_INQUIRY) { return ESP_ERR_INVALID_ARG; } if (inq_len < ESP_BT_GAP_MIN_INQ_LEN || inq_len > ESP_BT_GAP_MAX_INQ_LEN) { return ESP_ERR_INVALID_ARG; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_START_DISCOVERY; arg.start_disc.mode = mode; arg.start_disc.inq_len = inq_len; arg.start_disc.num_rsps = num_rsps; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_cancel_discovery(void) { btc_msg_t msg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_CANCEL_DISCOVERY; return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_get_remote_services(esp_bd_addr_t remote_bda) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_GET_REMOTE_SERVICES; memcpy(&arg.bda, remote_bda, sizeof(bt_bdaddr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_uuid_t *uuid) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD; memcpy(&arg.get_rmt_srv_rcd.bda, remote_bda, sizeof(bt_bdaddr_t)); memcpy(&arg.get_rmt_srv_rcd.uuid, uuid, sizeof(esp_bt_uuid_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8_t *length) { if (!eir) { return NULL; } return BTM_CheckEirData(eir, type, length); } esp_err_t esp_bt_gap_config_eir_data(esp_bt_eir_data_t *eir_data) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (eir_data == NULL) { return ESP_ERR_INVALID_ARG; } if (eir_data->manufacturer_len > ESP_BT_EIR_MAX_LEN || eir_data->url_len > ESP_BT_EIR_MAX_LEN) { return ESP_ERR_INVALID_ARG; } if ((eir_data->manufacturer_len > 0 && eir_data->p_manufacturer_data == NULL) || (eir_data->url_len > 0 && eir_data->p_url == NULL)) { return ESP_ERR_INVALID_ARG; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_CONFIG_EIR; memcpy(&arg.config_eir, eir_data, sizeof(esp_bt_eir_data_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_cod(esp_bt_cod_t cod, esp_bt_cod_mode_t mode) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } switch (mode) { case ESP_BT_SET_COD_MAJOR_MINOR: case ESP_BT_SET_COD_SERVICE_CLASS: case ESP_BT_CLR_COD_SERVICE_CLASS: case ESP_BT_SET_COD_ALL: case ESP_BT_INIT_COD: break; default: return ESP_ERR_INVALID_ARG; break; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_COD; arg.set_cod.mode = mode; memcpy(&arg.set_cod.cod, &cod, sizeof(esp_bt_cod_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_get_cod(esp_bt_cod_t *cod) { return btc_gap_bt_get_cod(cod); } esp_err_t esp_bt_gap_read_rssi_delta(esp_bd_addr_t remote_addr) { btc_msg_t msg; btc_gap_bt_args_t arg; msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_READ_RSSI_DELTA; memcpy(arg.read_rssi_delta.bda.address, remote_addr, sizeof(esp_bd_addr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_remove_bond_device(esp_bd_addr_t bd_addr) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_REMOVE_BOND_DEVICE; memcpy(arg.rm_bond_device.bda.address, bd_addr, sizeof(esp_bd_addr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } int esp_bt_gap_get_bond_device_num(void) { if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } return btc_storage_get_num_bt_bond_devices(); } esp_err_t esp_bt_gap_get_bond_device_list(int *dev_num, esp_bd_addr_t *dev_list) { int ret; if (dev_num == NULL || dev_list == NULL) { return ESP_ERR_INVALID_ARG; } if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } ret = btc_storage_get_bonded_bt_devices_list((bt_bdaddr_t *)dev_list, dev_num); return (ret == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_pin(esp_bt_pin_type_t pin_type, uint8_t pin_code_len, esp_bt_pin_code_t pin_code) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_PIN_TYPE; arg.set_pin_type.pin_type = pin_type; if (pin_type == ESP_BT_PIN_TYPE_FIXED){ arg.set_pin_type.pin_code_len = pin_code_len; memcpy(arg.set_pin_type.pin_code, pin_code, pin_code_len); } else { arg.set_pin_type.pin_code_len = 0; memset(arg.set_pin_type.pin_code, 0, ESP_BT_PIN_CODE_LEN); } return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_pin_reply(esp_bd_addr_t bd_addr, bool accept, uint8_t pin_code_len, esp_bt_pin_code_t pin_code) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_PIN_REPLY; arg.pin_reply.accept = accept; arg.pin_reply.pin_code_len = pin_code_len; memcpy(arg.pin_reply.bda.address, bd_addr, sizeof(esp_bd_addr_t)); memcpy(arg.pin_reply.pin_code, pin_code, pin_code_len); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_security_param(esp_bt_sp_param_t param_type, void *value, uint8_t len) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (!(bluedriod_config_get()->get_ssp_enabled())) { ESP_LOGE(TAG, "%s is not supported when `ssp_en` in `esp_bluedroid_config_t` is disabled!", __func__); return ESP_ERR_NOT_SUPPORTED; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_SECURITY_PARAM; arg.set_security_param.param_type = param_type; arg.set_security_param.len = len; arg.set_security_param.value = value; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_ssp_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t passkey) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (!(bluedriod_config_get()->get_ssp_enabled())) { ESP_LOGE(TAG, "%s is not supported when `ssp_en` in `esp_bluedroid_config_t` is disabled!", __func__); return ESP_ERR_NOT_SUPPORTED; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_PASSKEY_REPLY; arg.passkey_reply.accept = accept; arg.passkey_reply.passkey = passkey; memcpy(arg.passkey_reply.bda.address, bd_addr, sizeof(esp_bd_addr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_ssp_confirm_reply(esp_bd_addr_t bd_addr, bool accept) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (!(bluedriod_config_get()->get_ssp_enabled())) { ESP_LOGE(TAG, "%s is not supported when `ssp_en` in `esp_bluedroid_config_t` is disabled!", __func__); return ESP_ERR_NOT_SUPPORTED; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_CONFIRM_REPLY; arg.confirm_reply.accept = accept; memcpy(arg.confirm_reply.bda.address, bd_addr, sizeof(esp_bd_addr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_afh_channels(esp_bt_gap_afh_channels channels) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_AFH_CHANNELS; memcpy(&arg.set_afh_channels.channels, channels, ESP_BT_GAP_AFH_CHANNELS_LEN); arg.set_afh_channels.channels[ESP_BT_GAP_AFH_CHANNELS_LEN -1] &= 0x7F; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_read_remote_name(esp_bd_addr_t remote_bda) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_READ_REMOTE_NAME; memcpy(&arg.rmt_name_bda, remote_bda, sizeof(bt_bdaddr_t)); return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_qos(esp_bd_addr_t remote_bda, uint32_t t_poll) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (t_poll < ESP_BT_GAP_TPOLL_MIN || t_poll > ESP_BT_GAP_TPOLL_MAX) { return ESP_ERR_INVALID_ARG; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_QOS; memcpy(&arg.set_qos.bda, remote_bda, sizeof(bt_bdaddr_t)); arg.set_qos.t_poll = t_poll; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_page_timeout(uint16_t page_to) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if (page_to < HCI_MIN_PAGE_TOUT) { return ESP_ERR_INVALID_ARG; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT; arg.set_page_to.page_to = page_to; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_get_page_timeout(void) { btc_msg_t msg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_GET_PAGE_TIMEOUT; return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_acl_pkt_types(esp_bd_addr_t remote_bda, uint16_t pkt_types) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES; memcpy(&arg.set_acl_pkt_types.bda, remote_bda, sizeof(bt_bdaddr_t)); arg.set_acl_pkt_types.pkt_types = pkt_types; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_set_device_name(const char *name) { btc_msg_t msg; btc_gap_bt_args_t arg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } if ((!name) || (strlen(name) > BTC_MAX_LOC_BD_NAME_LEN)) { return ESP_ERR_INVALID_ARG; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_SET_DEV_NAME; arg.bt_set_dev_name.device_name = (char *)name; return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_bt_gap_get_device_name(void) { btc_msg_t msg; if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BT; msg.act = BTC_GAP_BT_ACT_GET_DEV_NAME; return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } #endif /* #if BTC_GAP_BT_INCLUDED == TRUE */