Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a73d963 authored by Ray's avatar Ray Committed by Ray Kuo
Browse files

BQR: Add Bluetooth Quality Report feature

Bluetooth disconnects, voice and audio quality issues are sometimes hard
to debug without an OTA (Over The Air) log.
For debugging this kind of issue we would need to identify it belongs to
the host, Bluetooth controller/firmware, environment or the remote
Bluetooth device.
This feature would route the link and firmware/controller stats (ex: TX
power level, RSSI, Unused AFH channel count...) to the host when quality
events happen.

Quality Monitoring Mode:
The controller will periodically send Bluetooth Quality VSE 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 will report Approaching LSTO event to the host.

A2DP Audio Choppy:
When audio stall, the controller will report A2DP Audio Choppy event to
the host.

(e)SCO Voice Choppy:
The controller will report (e)SCO Voice Choppy event to the host if the
voice quality might be bad.

Bug: 111384296
Test: - Verified that all functionalites with the Bluetooth controller /
        firmware which supports Bluetooth Quality Report VSC
	(OpCode: 0xFD5E) and Bluetooth Quality Report (Sub-event code:
	0x58) of VSE.
      - Verified that this feature could work on both the A2DP HW
        offload and non-offload modes.

Change-Id: I3fd3000bace7606855cac3b9b87134499c0ca891
parent d2f59463
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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",
+264 −0
Original line number Diff line number Diff line
/*
 * 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_
+2 −0
Original line number Diff line number Diff line
@@ -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
+309 −0
Original line number Diff line number Diff line
/*
 * 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
+3 −1
Original line number Diff line number Diff line
@@ -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;

Loading