diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 60a6c69cc6b05920f527da724c706e1af6213acc..7683e16719fe89c738af8efdddca64e3ec9e2832 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -53,6 +53,7 @@ cc_library_static { "src/btif_avrcp_audio_track.cc", "src/btif_ble_advertiser.cc", "src/btif_ble_scanner.cc", + "src/btif_bqr.cc", "src/btif_config.cc", "src/btif_config_transcode.cc", "src/btif_core.cc", diff --git a/system/btif/include/btif_bqr.h b/system/btif/include/btif_bqr.h new file mode 100644 index 0000000000000000000000000000000000000000..98c2693b8f48d4457a9c80c003041252b9462ea8 --- /dev/null +++ b/system/btif/include/btif_bqr.h @@ -0,0 +1,264 @@ +/* + * Copyright 2019 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. + */ + +#ifndef BTIF_BQR_H_ +#define BTIF_BQR_H_ + +#include "btm_api_types.h" +#include "common/leaky_bonded_queue.h" + +namespace bluetooth { +namespace bqr { + +// Bluetooth Quality Report (BQR) +// +// It is a feature to start the mechanism in the Bluetooth controller to report +// Bluetooth Quality event to the host and there are four options could be +// enabled: +// [Quality Monitoring Mode] +// The controller shall periodically send Bluetooth Quality Report sub-event +// to the host. +// +// [Approaching LSTO] +// Once no packets are received from the connected Bluetooth device for a +// duration longer than the half of LSTO (Link Supervision TimeOut) value, +// the controller shall report Approaching LSTO event to the host. +// +// [A2DP Audio Choppy] +// When the controller detects the factors which will cause audio choppy, +// the controller shall report A2DP Audio Choppy event to the host. +// +// [(e)SCO Voice Choppy] +// When the controller detects the factors which will cause voice choppy, +// the controller shall report (e)SCO Voice Choppy event to the host. + +// Bit masks for the selected quality event reporting. +static constexpr uint32_t kQualityEventMaskAllOff = 0; +static constexpr uint32_t kQualityEventMaskMonitorMode = 0x00000001; +static constexpr uint32_t kQualityEventMaskApproachLsto = 0x00000002; +static constexpr uint32_t kQualityEventMaskA2dpAudioChoppy = 0x00000004; +static constexpr uint32_t kQualityEventMaskScoVoiceChoppy = 0x00000008; +static constexpr uint32_t kQualityEventMaskAll = + kQualityEventMaskMonitorMode | kQualityEventMaskApproachLsto | + kQualityEventMaskA2dpAudioChoppy | kQualityEventMaskScoVoiceChoppy; +// Define the minimum time interval (in ms) of quality event reporting for the +// selected quality event(s). Controller Firmware should not report the next +// event within the defined time interval. +static constexpr uint16_t kMinReportIntervalNoLimit = 0; +static constexpr uint16_t kMinReportIntervalMaxMs = 0xFFFF; +// Total length of all BQR parameters except Vendor Specific Parameters. +static constexpr uint8_t kBqrParamTotalLen = 48; +// Warning criteria of the RSSI value. +static constexpr int8_t kCriWarnRssi = -80; +// Warning criteria of the unused AFH channel count. +static constexpr uint8_t kCriWarnUnusedCh = 55; +// The queue size of recording the BQR events. +static constexpr uint8_t kBqrEventQueueSize = 25; +// The Property of BQR event mask configuration. +static constexpr const char* kpPropertyEventMask = + "persist.bluetooth.bqr.eventmask"; +// The Property of BQR minimum report interval configuration. +static constexpr const char* kpPropertyReportInt = + "persist.bluetooth.bqr.interval"; + +// Action definition +// +// Action to Add, Delete or Clear the reporting of quality event(s). +// Delete will clear specific quality event(s) reporting. Clear will clear all +// quality events reporting. +enum BqrReportAction : uint8_t { + REPORT_ACTION_ADD = 0x00, + REPORT_ACTION_DELETE = 0x01, + REPORT_ACTION_CLEAR = 0x02 +}; + +// Report ID definition +enum BqrQualityReportId : uint8_t { + QUALITY_REPORT_ID_MONITOR_MODE = 0x01, + QUALITY_REPORT_ID_APPROACH_LSTO = 0x02, + QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03, + QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04 +}; + +// Packet Type definition +enum BqrPacketType : uint8_t { + PACKET_TYPE_ID = 0x01, + PACKET_TYPE_NULL, + PACKET_TYPE_POLL, + PACKET_TYPE_FHS, + PACKET_TYPE_HV1, + PACKET_TYPE_HV2, + PACKET_TYPE_HV3, + PACKET_TYPE_DV, + PACKET_TYPE_EV3, + PACKET_TYPE_EV4, + PACKET_TYPE_EV5, + PACKET_TYPE_2EV3, + PACKET_TYPE_2EV5, + PACKET_TYPE_3EV3, + PACKET_TYPE_3EV5, + PACKET_TYPE_DM1, + PACKET_TYPE_DH1, + PACKET_TYPE_DM3, + PACKET_TYPE_DH3, + PACKET_TYPE_DM5, + PACKET_TYPE_DH5, + PACKET_TYPE_AUX1, + PACKET_TYPE_2DH1, + PACKET_TYPE_2DH3, + PACKET_TYPE_2DH5, + PACKET_TYPE_3DH1, + PACKET_TYPE_3DH3, + PACKET_TYPE_3DH5 +}; + +// Configuration Parameters +typedef struct { + BqrReportAction report_action; + uint32_t quality_event_mask; + uint16_t minimum_report_interval; +} BqrConfiguration; + +// BQR sub-event of Vendor Specific Event +class BqrVseSubEvt { + public: + // Parse the Bluetooth Quality Report VSE sub-event. + // + // @param length Total length of all parameters contained in the sub-event. + // @param p_param_buf A pointer to the parameters contained in the sub-event. + // @return false If the parameter total length is abnormal. + // true If all parameters are parsed successfully. + bool ParseBqrEvt(uint8_t length, uint8_t* p_param_buf); + + // Get a string representation of the Bluetooth Quality event. + // + // @return a string representation of the Bluetooth Quality event. + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, const BqrVseSubEvt& a) { + return os << a.ToString(); + } + + virtual ~BqrVseSubEvt() = default; + + // Quality report ID. + uint8_t quality_report_id_; + // Packet type of the connection. + uint8_t packet_types_; + // Connection handle of the connection. + uint16_t connection_handle_; + // Performing Role for the connection. + uint8_t connection_role_; + // Current Transmit Power Level for the connection. This value is the same as + // the controller's response to the HCI_Read_Transmit_Power_Level HCI command. + uint8_t tx_power_level_; + // Received Signal Strength Indication (RSSI) value for the connection. This + // value is an absolute receiver signal strength value. + int8_t rssi_; + // Signal-to-Noise Ratio (SNR) value for the connection. It is the average + // SNR of all the channels used by the link currently. + uint8_t snr_; + // Indicates the number of unused channels in AFH_channel_map. + uint8_t unused_afh_channel_count_; + // Indicates the number of the channels which are interfered and quality is + // bad but are still selected for AFH. + uint8_t afh_select_unideal_channel_count_; + // Current Link Supervision Timeout Setting. + uint16_t lsto_; + // Piconet Clock for the specified Connection_Handle. This value is the same + // as the controller's response to HCI_Read_Clock HCI command with the + // parameter "Which_Clock" of 0x01 (Piconet Clock). + uint32_t connection_piconet_clock_; + // The count of retransmission. + uint32_t retransmission_count_; + // The count of no RX. + uint32_t no_rx_count_; + // The count of NAK (Negative Acknowledge). + uint32_t nak_count_; + // Timestamp of last TX ACK. + uint32_t last_tx_ack_timestamp_; + // The count of Flow-off (STOP). + uint32_t flow_off_count_; + // Timestamp of last Flow-on (GO). + uint32_t last_flow_on_timestamp_; + // Buffer overflow count (how many bytes of TX data are dropped) since the + // last event. + uint32_t buffer_overflow_bytes_; + // Buffer underflow count (in byte). + uint32_t buffer_underflow_bytes_; + // Timestamp of receiving BQR VSE sub-event + std::tm tm_timestamp_; +}; + +// Get a string representation of the Quality Report ID. +// +// @param quality_report_id The quality report ID to convert. +// @return a string representation of the Quality Report ID. +std::string QualityReportIdToString(uint8_t quality_report_id); + +// Get a string representation of the Packet Type. +// +// @param packet_type The packet type to convert. +// @return a string representation of the Packet Type. +std::string PacketTypeToString(uint8_t packet_type); + +// Enable/Disable Bluetooth Quality Report mechanism. +// +// Which Quality event will be enabled is according to the setting of the +// property "persist.bluetooth.bqr.eventmask". +// And the minimum time interval of quality event reporting depends on the +// setting of property "persist.bluetooth.bqr.interval". +// +// @param is_enable True/False to enable/disable Bluetooth Quality Report +// mechanism in the Bluetooth controller. +void EnableBtQualityReport(bool is_enable); + +// Dump Bluetooth Quality Report information. +// +// @param fd The file descriptor to use for dumping information. +void DebugDump(int fd); + +// Configure Bluetooth Quality Report setting to the Bluetooth controller. +// +// @param bqr_config The struct of configuration parameters. +void ConfigureBqr(const BqrConfiguration& bqr_config); + +// Invoked on completion of Bluetooth Quality Report configuration. Then it will +// Register/Unregister for receiving VSE - Bluetooth Quality Report sub event. +// +// @param current_evt_mask Indicates current quality event bit mask setting in +// the Bluetooth controller. +void ConfigureBqrCmpl(uint32_t current_evt_mask); + +// Callback invoked on completion of vendor specific Bluetooth Quality Report +// command. +// +// @param p_vsc_cmpl_params A pointer to the parameters contained in the vendor +// specific command complete event. +void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params); + +// Record a new incoming Bluetooth Quality Report in quality event queue. +// +// @param len Lengths of the quality report sent from the Bluetooth +// controller. +// @param p_quality_report A pointer to the quality report which is sent from +// the Bluetooth controller via Vendor Specific Event. +void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream); + +} // namespace bqr +} // namespace bluetooth + +#endif // BTIF_BQR_H_ diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index 5e04e098fbcac7c7b15b5deb19f30340924d54e0..1faca2dcb4349cee515539a9b0ebc0ed5f160f80 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/btif/src/bluetooth.cc @@ -53,6 +53,7 @@ #include "btif_a2dp.h" #include "btif_api.h" #include "btif_av.h" +#include "btif_bqr.h" #include "btif_config.h" #include "btif_debug.h" #include "btif_debug_btsnoop.h" @@ -317,6 +318,7 @@ static void dump(int fd, const char** arguments) { alarm_debug_dump(fd); HearingAid::DebugDump(fd); connection_manager::dump(fd); + bluetooth::bqr::DebugDump(fd); #if (BTSNOOP_MEM == TRUE) btif_debug_btsnoop_dump(fd); #endif diff --git a/system/btif/src/btif_bqr.cc b/system/btif/src/btif_bqr.cc new file mode 100644 index 0000000000000000000000000000000000000000..cf7abeddbf79ff35b674dc29493cc565f77be637 --- /dev/null +++ b/system/btif/src/btif_bqr.cc @@ -0,0 +1,309 @@ +/* + * Copyright 2019 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 "btif_bqr.h" +#include "btif_dm.h" +#include "common/leaky_bonded_queue.h" +#include "osi/include/properties.h" +#include "stack/btm/btm_int.h" + +namespace bluetooth { +namespace bqr { + +using bluetooth::common::LeakyBondedQueue; +using std::chrono::system_clock; + +// The instance of BQR event queue +static std::unique_ptr<LeakyBondedQueue<BqrVseSubEvt>> kpBqrEventQueue( + new LeakyBondedQueue<BqrVseSubEvt>(kBqrEventQueueSize)); + +bool BqrVseSubEvt::ParseBqrEvt(uint8_t length, uint8_t* p_param_buf) { + if (length < kBqrParamTotalLen) { + LOG(FATAL) << __func__ + << ": Parameter total length: " << std::to_string(length) + << " is abnormal. It shall be not shorter than: " + << std::to_string(kBqrParamTotalLen); + return false; + } + + STREAM_TO_UINT8(quality_report_id_, p_param_buf); + STREAM_TO_UINT8(packet_types_, p_param_buf); + STREAM_TO_UINT16(connection_handle_, p_param_buf); + STREAM_TO_UINT8(connection_role_, p_param_buf); + STREAM_TO_UINT8(tx_power_level_, p_param_buf); + STREAM_TO_INT8(rssi_, p_param_buf); + STREAM_TO_UINT8(snr_, p_param_buf); + STREAM_TO_UINT8(unused_afh_channel_count_, p_param_buf); + STREAM_TO_UINT8(afh_select_unideal_channel_count_, p_param_buf); + STREAM_TO_UINT16(lsto_, p_param_buf); + STREAM_TO_UINT32(connection_piconet_clock_, p_param_buf); + STREAM_TO_UINT32(retransmission_count_, p_param_buf); + STREAM_TO_UINT32(no_rx_count_, p_param_buf); + STREAM_TO_UINT32(nak_count_, p_param_buf); + STREAM_TO_UINT32(last_tx_ack_timestamp_, p_param_buf); + STREAM_TO_UINT32(flow_off_count_, p_param_buf); + STREAM_TO_UINT32(last_flow_on_timestamp_, p_param_buf); + STREAM_TO_UINT32(buffer_overflow_bytes_, p_param_buf); + STREAM_TO_UINT32(buffer_underflow_bytes_, p_param_buf); + + const auto now = system_clock::to_time_t(system_clock::now()); + localtime_r(&now, &tm_timestamp_); + + return true; +} + +std::string BqrVseSubEvt::ToString() const { + std::stringstream ss_return_string; + ss_return_string << QualityReportIdToString(quality_report_id_) + << ", Handle: " << loghex(connection_handle_) << ", " + << PacketTypeToString(packet_types_) << ", " + << ((connection_role_ == 0) ? "Master" : "Slave ") + << ", PwLv: " << loghex(tx_power_level_) + << ", RSSI: " << std::to_string(rssi_) + << ", SNR: " << std::to_string(snr_) << ", UnusedCh: " + << std::to_string(unused_afh_channel_count_) + << ", UnidealCh: " + << std::to_string(afh_select_unideal_channel_count_) + << ", ReTx: " << std::to_string(retransmission_count_) + << ", NoRX: " << std::to_string(no_rx_count_) + << ", NAK: " << std::to_string(nak_count_) + << ", FlowOff: " << std::to_string(flow_off_count_) + << ", OverFlow: " << std::to_string(buffer_overflow_bytes_) + << ", UndFlow: " << std::to_string(buffer_underflow_bytes_); + return ss_return_string.str(); +} + +std::string QualityReportIdToString(uint8_t quality_report_id) { + switch (quality_report_id) { + case QUALITY_REPORT_ID_MONITOR_MODE: + return "Monitoring "; + case QUALITY_REPORT_ID_APPROACH_LSTO: + return "Appro LSTO "; + case QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY: + return "A2DP Choppy"; + case QUALITY_REPORT_ID_SCO_VOICE_CHOPPY: + return "SCO Choppy "; + default: + return "Invalid "; + } +} + +std::string PacketTypeToString(uint8_t packet_type) { + switch (packet_type) { + case PACKET_TYPE_ID: + return "ID"; + case PACKET_TYPE_NULL: + return "NULL"; + case PACKET_TYPE_POLL: + return "POLL"; + case PACKET_TYPE_FHS: + return "FHS"; + case PACKET_TYPE_HV1: + return "HV1"; + case PACKET_TYPE_HV2: + return "HV2"; + case PACKET_TYPE_HV3: + return "HV3"; + case PACKET_TYPE_DV: + return "DV"; + case PACKET_TYPE_EV3: + return "EV3"; + case PACKET_TYPE_EV4: + return "EV4"; + case PACKET_TYPE_EV5: + return "EV5"; + case PACKET_TYPE_2EV3: + return "2EV3"; + case PACKET_TYPE_2EV5: + return "2EV5"; + case PACKET_TYPE_3EV3: + return "3EV3"; + case PACKET_TYPE_3EV5: + return "3EV5"; + case PACKET_TYPE_DM1: + return "DM1"; + case PACKET_TYPE_DH1: + return "DH1"; + case PACKET_TYPE_DM3: + return "DM3"; + case PACKET_TYPE_DH3: + return "DH3"; + case PACKET_TYPE_DM5: + return "DM5"; + case PACKET_TYPE_DH5: + return "DH5"; + case PACKET_TYPE_AUX1: + return "AUX1"; + case PACKET_TYPE_2DH1: + return "2DH1"; + case PACKET_TYPE_2DH3: + return "2DH3"; + case PACKET_TYPE_2DH5: + return "2DH5"; + case PACKET_TYPE_3DH1: + return "3DH1"; + case PACKET_TYPE_3DH3: + return "3DH3"; + case PACKET_TYPE_3DH5: + return "3DH5"; + default: + return "UnKnown "; + } +} + +void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream) { + std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>(); + if (!p_bqr_event->ParseBqrEvt(length, p_stream)) { + LOG(WARNING) << __func__ << ": Fail to parse BQR sub event."; + return; + } + + LOG(WARNING) << *p_bqr_event; + kpBqrEventQueue->Enqueue(p_bqr_event.release()); +} + +void ConfigureBqrCmpl(uint32_t current_evt_mask) { + LOG(INFO) << __func__ << ": current_evt_mask: " << loghex(current_evt_mask); + // (Un)Register for VSE of Bluetooth Quality Report sub event + tBTM_STATUS btm_status = BTM_BT_Quality_Report_VSE_Register( + current_evt_mask > kQualityEventMaskAllOff, AddBqrEventToQueue); + + if (btm_status != BTM_SUCCESS) { + LOG(ERROR) << __func__ << ": Fail to (un)register VSE of BQR sub event." + << " status: " << btm_status; + } +} + +void EnableBtQualityReport(bool is_enable) { + LOG(INFO) << __func__ << ": is_enable: " << logbool(is_enable); + + char bqr_prop_evtmask[PROPERTY_VALUE_MAX] = {0}; + char bqr_prop_interval[PROPERTY_VALUE_MAX] = {0}; + osi_property_get(kpPropertyEventMask, bqr_prop_evtmask, ""); + osi_property_get(kpPropertyReportInt, bqr_prop_interval, ""); + + if (strlen(bqr_prop_evtmask) == 0 || strlen(bqr_prop_interval) == 0) { + LOG(WARNING) << __func__ << ": Bluetooth Quality Report is disabled." + << " bqr_prop_evtmask: " << bqr_prop_evtmask + << ", bqr_prop_interval: " << bqr_prop_interval; + return; + } + + BqrConfiguration bqr_config = {}; + + if (is_enable) { + bqr_config.report_action = REPORT_ACTION_ADD; + bqr_config.quality_event_mask = + static_cast<uint32_t>(atoi(bqr_prop_evtmask)); + bqr_config.minimum_report_interval = + static_cast<uint16_t>(atoi(bqr_prop_interval)); + } else { + bqr_config.report_action = REPORT_ACTION_CLEAR; + bqr_config.quality_event_mask = kQualityEventMaskAllOff; + bqr_config.minimum_report_interval = kMinReportIntervalNoLimit; + } + + LOG(INFO) << __func__ + << ": Event Mask: " << loghex(bqr_config.quality_event_mask) + << ", Interval: " << bqr_config.minimum_report_interval; + ConfigureBqr(bqr_config); +} + +void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params) { + if (p_vsc_cmpl_params->param_len < 1) { + LOG(FATAL) << __func__ + << ": The length of returned parameters is less than 1"; + return; + } + + uint8_t* p_event_param_buf = p_vsc_cmpl_params->p_param_buf; + uint8_t status = 0xff; + // [Return Parameter] | [Size] | [Purpose] + // Status | 1 octet | Command complete status + // Current_Quality_Event_Mask | 4 octets | Indicates current bit mask setting + STREAM_TO_UINT8(status, p_event_param_buf); + if (status != HCI_SUCCESS) { + LOG(FATAL) << __func__ + << ": Fail to configure BQR. status: " << loghex(status); + return; + } + + if (p_vsc_cmpl_params->param_len != 5) { + LOG(FATAL) << __func__ + << ": The length of returned parameters is not equal to 5: " + << std::to_string(p_vsc_cmpl_params->param_len); + return; + } + + uint32_t current_quality_event_mask = kQualityEventMaskAllOff; + STREAM_TO_UINT32(current_quality_event_mask, p_event_param_buf); + + LOG(INFO) << __func__ + << ", current event mask: " << loghex(current_quality_event_mask); + ConfigureBqrCmpl(current_quality_event_mask); +} + +void ConfigureBqr(const BqrConfiguration& bqr_config) { + if (bqr_config.report_action > REPORT_ACTION_CLEAR || + bqr_config.quality_event_mask > kQualityEventMaskAll || + bqr_config.minimum_report_interval > kMinReportIntervalMaxMs) { + LOG(FATAL) << __func__ << ": Invalid Parameter" + << ", Action: " << bqr_config.report_action + << ", Mask: " << loghex(bqr_config.quality_event_mask) + << ", Interval: " << bqr_config.minimum_report_interval; + return; + } + + LOG(INFO) << __func__ << ": Action: " << bqr_config.report_action + << ", Mask: " << loghex(bqr_config.quality_event_mask) + << ", Interval: " << bqr_config.minimum_report_interval; + + uint8_t param[sizeof(BqrConfiguration)]; + uint8_t* p_param = param; + UINT8_TO_STREAM(p_param, bqr_config.report_action); + UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask); + UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval); + + BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR_OPCODE_OCF, p_param - param, + param, BqrVscCompleteCallback); +} + +void DebugDump(int fd) { + dprintf(fd, "\nBT Quality Report Events: \n"); + + if (kpBqrEventQueue->Empty()) { + dprintf(fd, "Event queue is empty.\n"); + return; + } + + while (!kpBqrEventQueue->Empty()) { + std::unique_ptr<BqrVseSubEvt> p_event(kpBqrEventQueue->Dequeue()); + + bool warning = (p_event->rssi_ < kCriWarnRssi || + p_event->unused_afh_channel_count_ > kCriWarnUnusedCh); + + std::stringstream ss_timestamp; + ss_timestamp << std::put_time(&p_event->tm_timestamp_, "%m-%d %H:%M:%S"); + + dprintf(fd, "%c %s %s\n", warning ? '*' : ' ', ss_timestamp.str().c_str(), + p_event->ToString().c_str()); + } + + dprintf(fd, "\n"); +} + +} // namespace bqr +} // namespace bluetooth diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index dc6adcfc7c617a815b186d34e1cbf65f02f9aa5b..683834ab52757250bbcebe1ea677782625401396 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -50,6 +50,7 @@ #include "bta_gatt_api.h" #include "btif_api.h" #include "btif_av.h" +#include "btif_bqr.h" #include "btif_config.h" #include "btif_dm.h" #include "btif_hd.h" @@ -1606,7 +1607,7 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { ** and bonded_devices_info_cb */ btif_storage_load_bonded_devices(); - + bluetooth::bqr::EnableBtQualityReport(true); btif_enable_bluetooth_evt(p_data->enable.status); } break; @@ -1620,6 +1621,7 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { btif_in_execute_service_request(i, false); } } + bluetooth::bqr::EnableBtQualityReport(false); btif_disable_bluetooth_evt(); break; diff --git a/system/stack/btm/btm_devctl.cc b/system/stack/btm/btm_devctl.cc index 04721f83d7931bd7667613ce9ddb78c977a5c096..bc3fb5649acede756b5c847f967dc5e1e3607805 100644 --- a/system/stack/btm/btm_devctl.cc +++ b/system/stack/btm/btm_devctl.cc @@ -67,6 +67,7 @@ extern bluetooth::common::MessageLoopThread bt_startup_thread; static void btm_decode_ext_features_page(uint8_t page_number, const BD_FEATURES p_features); +static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, uint8_t* p_stream); /******************************************************************************* * @@ -865,3 +866,74 @@ void btm_report_device_status(tBTM_DEV_STATUS status) { /* Call the call back to pass the device status to application */ if (p_cb) (*p_cb)(status); } + +/******************************************************************************* + * + * Function BTM_BT_Quality_Report_VSE_CBack + * + * Description Callback invoked on receiving of Vendor Specific Events. + * This function will call registered BQR report receiver if + * Bluetooth Quality Report sub-event is identified. + * + * Parameters: length - Lengths of all of the parameters contained in the + * Vendor Specific Event. + * p_stream - A pointer to the quality report which is sent + * from the Bluetooth controller via Vendor Specific Event. + * + ******************************************************************************/ +static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, uint8_t* p_stream) { + if (length == 0) { + LOG(WARNING) << __func__ << ": Lengths of all of the parameters are zero."; + return; + } + + uint8_t sub_event = 0; + STREAM_TO_UINT8(sub_event, p_stream); + length--; + + if (sub_event == HCI_VSE_SUBCODE_BQR_SUB_EVT) { + LOG(INFO) << __func__ + << ": BQR sub event, report length: " << std::to_string(length); + + if (btm_cb.p_bqr_report_receiver == nullptr) { + LOG(WARNING) << __func__ << ": No registered report receiver."; + return; + } + + btm_cb.p_bqr_report_receiver(length, p_stream); + } +} + +/******************************************************************************* + * + * Function BTM_BT_Quality_Report_VSE_Register + * + * Description Register/Deregister for Bluetooth Quality Report VSE sub + * event Callback. + * + * Parameters: is_register - True/False to register/unregister for VSE. + * p_bqr_report_receiver - The receiver for receiving Bluetooth + * Quality Report VSE sub event. + * + ******************************************************************************/ +tBTM_STATUS BTM_BT_Quality_Report_VSE_Register( + bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver) { + tBTM_STATUS retval = + BTM_RegisterForVSEvents(BTM_BT_Quality_Report_VSE_CBack, is_register); + + if (retval != BTM_SUCCESS) { + LOG(WARNING) << __func__ << ": Fail to (un)register VSEvents: " << retval + << ", is_register: " << logbool(is_register); + return retval; + } + + if (is_register) { + btm_cb.p_bqr_report_receiver = p_bqr_report_receiver; + } else { + btm_cb.p_bqr_report_receiver = nullptr; + } + + LOG(INFO) << __func__ << ": Success to (un)register VSEvents." + << " is_register: " << logbool(is_register); + return retval; +} diff --git a/system/stack/btm/btm_int.h b/system/stack/btm/btm_int.h index d06322270c1778d557328a5565d55c35288c8f13..8f2274b1f4ddf7f19c66069ce9e93e839c8c6865 100644 --- a/system/stack/btm/btm_int.h +++ b/system/stack/btm/btm_int.h @@ -191,6 +191,8 @@ extern void btm_inq_db_reset(void); extern void btm_vendor_specific_evt(uint8_t* p, uint8_t evt_len); extern void btm_delete_stored_link_key_complete(uint8_t* p); extern void btm_report_device_status(tBTM_DEV_STATUS status); +extern tBTM_STATUS BTM_BT_Quality_Report_VSE_Register( + bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver); /* Internal functions provided by btm_dev.cc ********************************************* diff --git a/system/stack/btm/btm_int_types.h b/system/stack/btm/btm_int_types.h index 7e51ff93820125e3c10ac2f279ee91550caaa4b1..a0460b1c0eb9f1348f9b6da612a5e7270478d5d1 100644 --- a/system/stack/btm/btm_int_types.h +++ b/system/stack/btm/btm_int_types.h @@ -18,6 +18,7 @@ #ifndef BTM_INT_TYPES_H #define BTM_INT_TYPES_H +#include "btif/include/btif_bqr.h" #include "btm_api_types.h" #include "btm_ble_api_types.h" #include "btm_ble_int_types.h" @@ -724,6 +725,9 @@ typedef struct { #define CONN_ORIENT_ORIG true typedef bool CONNECTION_TYPE; +// Bluetooth Quality Report - Report receiver +typedef void(tBTM_BT_QUALITY_REPORT_RECEIVER)(uint8_t len, uint8_t* p_stream); + /* Define a structure to hold all the BTM data */ @@ -828,6 +832,8 @@ typedef struct { tBTM_SEC_QUEUE_ENTRY format */ char state_temp_buffer[BTM_STATE_BUFFER_SIZE]; + // BQR Receiver + tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver; } tBTM_CB; /* security action for L2CAP COC channels */ diff --git a/system/stack/include/hcidefs.h b/system/stack/include/hcidefs.h index db58163b60ce20132aaec72f4f115fc1834d645e..ef87b5b615d3d5f0c68f6199c43d47aad733de29 100644 --- a/system/stack/include/hcidefs.h +++ b/system/stack/include/hcidefs.h @@ -423,6 +423,9 @@ /* A2DP offload OCF */ #define HCI_CONTROLLER_A2DP_OPCODE_OCF (0x015D | HCI_GRP_VENDOR_SPECIFIC) +/* Bluetooth Quality Report OCF */ +#define HCI_CONTROLLER_BQR_OPCODE_OCF (0x015E | HCI_GRP_VENDOR_SPECIFIC) + /* subcode for multi adv feature */ #define BTM_BLE_MULTI_ADV_SET_PARAM 0x01 #define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA 0x02 @@ -449,6 +452,9 @@ /* debug info sub event */ #define HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT 0x57 +/* Bluetooth Quality Report sub event */ +#define HCI_VSE_SUBCODE_BQR_SUB_EVT 0x58 + /* LE supported states definition */ #define HCI_LE_ADV_STATE 0x00000001 #define HCI_LE_SCAN_STATE 0x00000002