| /****************************************************************************** |
| * |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| #include "ble_advertiser_hci_interface.h" |
| #include <base/callback.h> |
| #include <base/logging.h> |
| #include <queue> |
| #include <utility> |
| #include "btm_api.h" |
| #include "btm_ble_api.h" |
| |
| #define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8 |
| #define BTM_BLE_MULTI_ADV_ENB_LEN 3 |
| #define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24 |
| #define BTM_BLE_AD_DATA_LEN 31 |
| #define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3) |
| |
| #define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1 |
| #define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6 |
| #define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15 |
| #define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31 |
| #define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31 |
| |
| using status_cb = BleAdvertiserHciInterface::status_cb; |
| |
| typedef void (*hci_cmd_complete_cb)(uint16_t opcode, uint8_t *return_parameters, |
| uint16_t return_parameters_length); |
| extern void btu_hcif_send_cmd_with_cb(uint16_t opcode, uint8_t *params, |
| uint8_t params_len, |
| hci_cmd_complete_cb cb); |
| |
| namespace { |
| BleAdvertiserHciInterface *instance = nullptr; |
| std::queue<std::pair<uint8_t, status_cb>> *pending_ops = nullptr; |
| |
| void btm_ble_multi_adv_vsc_cmpl_cback(tBTM_VSC_CMPL *p_params) { |
| uint8_t status, subcode; |
| uint8_t *p = p_params->p_param_buf; |
| uint16_t len = p_params->param_len; |
| |
| // All multi-adv commands respond with status and inst_id. |
| LOG_ASSERT(len == 2) << "Received bad response length to multi-adv VSC"; |
| |
| STREAM_TO_UINT8(status, p); |
| STREAM_TO_UINT8(subcode, p); |
| |
| VLOG(1) << "subcode = " << +subcode << ", status: " << +status; |
| |
| auto pending_op = pending_ops->front(); |
| uint8_t opcode = pending_op.first; |
| pending_ops->pop(); |
| |
| if (opcode != subcode) { |
| LOG(ERROR) << "unexpected VSC cmpl, expect: " << +subcode |
| << " get: " << +opcode; |
| return; |
| } |
| |
| pending_op.second.Run(status); |
| } |
| |
| class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface { |
| void SendVscMultiAdvCmd(uint8_t param_len, uint8_t *param_buf, |
| status_cb command_complete) { |
| BTM_VendorSpecificCommand(HCI_BLE_MULTI_ADV_OCF, param_len, param_buf, |
| btm_ble_multi_adv_vsc_cmpl_cback); |
| pending_ops->push(std::make_pair(param_buf[0], command_complete)); |
| } |
| |
| void ReadInstanceCount( |
| base::Callback<void(uint8_t /* inst_cnt*/)> cb) override { |
| cb.Run(BTM_BleMaxMultiAdvInstanceCount()); |
| } |
| |
| void SetParameters(uint8_t adv_int_min, uint8_t adv_int_max, |
| uint8_t advertising_type, uint8_t own_address_type, |
| BD_ADDR own_address, uint8_t direct_address_type, |
| BD_ADDR direct_address, uint8_t channel_map, |
| uint8_t filter_policy, uint8_t inst_id, uint8_t tx_power, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN]; |
| memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN); |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM); |
| UINT16_TO_STREAM(pp, adv_int_min); |
| UINT16_TO_STREAM(pp, adv_int_max); |
| UINT8_TO_STREAM(pp, advertising_type); |
| UINT8_TO_STREAM(pp, own_address_type); |
| BDADDR_TO_STREAM(pp, own_address); |
| UINT8_TO_STREAM(pp, direct_address_type); |
| BDADDR_TO_STREAM(pp, direct_address); |
| UINT8_TO_STREAM(pp, channel_map); |
| UINT8_TO_STREAM(pp, filter_policy); |
| UINT8_TO_STREAM(pp, inst_id); |
| UINT8_TO_STREAM(pp, tx_power); |
| |
| SendVscMultiAdvCmd(BTM_BLE_MULTI_ADV_SET_PARAM_LEN, param, |
| command_complete); |
| } |
| |
| void SetAdvertisingData(uint8_t data_length, uint8_t *data, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN]; |
| memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN); |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_ADV_DATA); |
| UINT8_TO_STREAM(pp, data_length); |
| ARRAY_TO_STREAM(pp, data, data_length); |
| param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = inst_id; |
| |
| SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param, |
| command_complete); |
| } |
| |
| void SetScanResponseData(uint8_t scan_response_data_length, |
| uint8_t *scan_response_data, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN]; |
| memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN); |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA); |
| UINT8_TO_STREAM(pp, scan_response_data_length); |
| ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length); |
| param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = inst_id; |
| |
| SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param, |
| command_complete); |
| } |
| |
| void SetRandomAddress(uint8_t random_address[6], uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN]; |
| memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN); |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR); |
| BDADDR_TO_STREAM(pp, random_address); |
| UINT8_TO_STREAM(pp, inst_id); |
| |
| SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN, param, |
| command_complete); |
| } |
| |
| void Enable(uint8_t advertising_enable, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[BTM_BLE_MULTI_ADV_ENB_LEN]; |
| memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN); |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_ENB); |
| UINT8_TO_STREAM(pp, advertising_enable); |
| UINT8_TO_STREAM(pp, inst_id); |
| |
| SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_ENB_LEN, param, |
| command_complete); |
| } |
| |
| public: |
| static void VendorSpecificEventCback(uint8_t length, uint8_t *p) { |
| VLOG(1) << __func__; |
| |
| LOG_ASSERT(p); |
| uint8_t sub_event, adv_inst, change_reason; |
| uint16_t conn_handle; |
| |
| STREAM_TO_UINT8(sub_event, p); |
| length--; |
| |
| if (sub_event != HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG || length != 4) { |
| return; |
| } |
| |
| STREAM_TO_UINT8(adv_inst, p); |
| STREAM_TO_UINT8(change_reason, p); |
| STREAM_TO_UINT16(conn_handle, p); |
| } |
| }; |
| |
| std::queue<std::pair<uint16_t, status_cb>> *legacy_pending_ops = nullptr; |
| void adv_cmd_cmpl_cback(uint16_t opcode, uint8_t *return_parameters, |
| uint16_t return_parameters_length) { |
| uint8_t status = *return_parameters; |
| |
| VLOG(1) << "opcode = " << +opcode << ", status: " << +status; |
| |
| auto pending_op = legacy_pending_ops->front(); |
| uint16_t pending_opc_opcode = pending_op.first; |
| legacy_pending_ops->pop(); |
| |
| if (opcode != pending_opc_opcode) { |
| LOG(ERROR) << "unexpected command complete, expect: " << +pending_opc_opcode |
| << " get: " << +opcode; |
| return; |
| } |
| |
| pending_op.second.Run(status); |
| } |
| |
| class BleAdvertiserLegacyHciInterfaceImpl : public BleAdvertiserHciInterface { |
| void SendAdvCmd(uint16_t opcode, uint8_t *param_buf, uint8_t param_buf_len, |
| status_cb command_complete) { |
| btu_hcif_send_cmd_with_cb(opcode, param_buf, param_buf_len, |
| adv_cmd_cmpl_cback); |
| |
| legacy_pending_ops->push(std::make_pair(opcode, command_complete)); |
| } |
| |
| void ReadInstanceCount( |
| base::Callback<void(uint8_t /* inst_cnt*/)> cb) override { |
| cb.Run(1); |
| } |
| |
| void SetParameters(uint8_t adv_int_min, uint8_t adv_int_max, |
| uint8_t advertising_type, uint8_t own_address_type, |
| BD_ADDR own_address, uint8_t direct_address_type, |
| BD_ADDR direct_address, uint8_t channel_map, |
| uint8_t filter_policy, uint8_t inst_id, uint8_t tx_power, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| |
| uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS]; |
| |
| uint8_t *pp = param; |
| UINT16_TO_STREAM(pp, adv_int_min); |
| UINT16_TO_STREAM(pp, adv_int_max); |
| UINT8_TO_STREAM(pp, advertising_type); |
| UINT8_TO_STREAM(pp, own_address_type); |
| UINT8_TO_STREAM(pp, direct_address_type); |
| BDADDR_TO_STREAM(pp, direct_address); |
| UINT8_TO_STREAM(pp, channel_map); |
| UINT8_TO_STREAM(pp, filter_policy); |
| |
| SendAdvCmd(HCI_BLE_WRITE_ADV_PARAMS, param, |
| HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS, command_complete); |
| } |
| |
| void SetAdvertisingData(uint8_t data_length, uint8_t *data, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| |
| uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1]; |
| |
| uint8_t *pp = param; |
| memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); |
| UINT8_TO_STREAM(pp, data_length); |
| ARRAY_TO_STREAM(pp, data, data_length); |
| |
| SendAdvCmd(HCI_BLE_WRITE_ADV_DATA, param, |
| HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete); |
| } |
| |
| void SetScanResponseData(uint8_t scan_response_data_length, |
| uint8_t *scan_response_data, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1]; |
| |
| uint8_t *pp = param; |
| memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); |
| UINT8_TO_STREAM(pp, scan_response_data_length); |
| ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length); |
| |
| SendAdvCmd(HCI_BLE_WRITE_SCAN_RSP_DATA, param, |
| HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete); |
| } |
| |
| void SetRandomAddress(uint8_t random_address[6], uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| |
| uint8_t param[HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD]; |
| |
| uint8_t *pp = param; |
| BDADDR_TO_STREAM(pp, random_address); |
| |
| SendAdvCmd(HCI_BLE_WRITE_RANDOM_ADDR, param, |
| HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD, command_complete); |
| } |
| |
| void Enable(uint8_t advertising_enable, uint8_t inst_id, |
| status_cb command_complete) override { |
| VLOG(1) << __func__; |
| uint8_t param[HCIC_PARAM_SIZE_WRITE_ADV_ENABLE]; |
| |
| uint8_t *pp = param; |
| UINT8_TO_STREAM(pp, advertising_enable); |
| |
| SendAdvCmd(HCI_BLE_WRITE_ADV_ENABLE, param, |
| HCIC_PARAM_SIZE_WRITE_ADV_ENABLE, command_complete); |
| } |
| }; |
| |
| } // namespace |
| |
| void BleAdvertiserHciInterface::Initialize() { |
| VLOG(1) << __func__; |
| LOG_ASSERT(instance == nullptr) << "Was already initialized."; |
| pending_ops = new std::queue<std::pair<uint8_t, status_cb>>(); |
| legacy_pending_ops = new std::queue<std::pair<uint16_t, status_cb>>(); |
| |
| if (BTM_BleMaxMultiAdvInstanceCount()) { |
| instance = new BleAdvertiserVscHciInterfaceImpl(); |
| BTM_RegisterForVSEvents( |
| BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, true); |
| } else { |
| instance = new BleAdvertiserLegacyHciInterfaceImpl(); |
| } |
| } |
| |
| BleAdvertiserHciInterface *BleAdvertiserHciInterface::Get() { return instance; } |
| |
| void BleAdvertiserHciInterface::CleanUp() { |
| VLOG(1) << __func__; |
| |
| if (BTM_BleMaxMultiAdvInstanceCount()) { |
| BTM_RegisterForVSEvents( |
| BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, false); |
| } |
| |
| delete pending_ops; |
| pending_ops = nullptr; |
| delete legacy_pending_ops; |
| legacy_pending_ops = nullptr; |
| delete instance; |
| instance = nullptr; |
| } |