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

Commit 91ae45af authored by Barry's avatar Barry
Browse files

Add BQRv6 parameter parser for upload to framework

- Add QUALITY_REPORT_ID_ENERGY_MONITOR in BqrLinkQualityEvent for
support BQR energy monitor event

- Add QUALITY_REPORT_ID_RF_STATS in BqrLinkQualityEvent for
support BQR RF stats event

- Add BqrEnergyMonitorEvent and BqrRFStatsEvent structure

- Add ParseBqrRFStatsEvt and ParseBqrRFStatsEvt function

Flag: com.android.bluetooth.flags.support_bluetooth_quality_report_v6
Bug: 364517559
Bug: 344812145

Test: m com.google.android.btservices
Test: manually verified
Change-Id: Ia67c28b2f4b61591f1f8ee1ef8b0569e3a2c7d01
parent defb2b18
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
@@ -204,8 +204,10 @@ enum BqrQualityReportId : uint8_t {
  QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03,
  QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04,
  QUALITY_REPORT_ID_ROOT_INFLAMMATION = 0x05,
  QUALITY_REPORT_ID_ENERGY_MONITOR = 0x06,
  QUALITY_REPORT_ID_LE_AUDIO_CHOPPY = 0x07,
  QUALITY_REPORT_ID_CONNECT_FAIL = 0x08,
  QUALITY_REPORT_ID_RF_STATS = 0x09,
  QUALITY_REPORT_ID_VENDOR_SPECIFIC_QUALITY = 0x10,
  QUALITY_REPORT_ID_LMP_LL_MESSAGE_TRACE = 0x11,
  QUALITY_REPORT_ID_BT_SCHEDULING_TRACE = 0x12,
@@ -334,6 +336,112 @@ typedef struct {
  const uint8_t* vendor_specific_parameter;
} BqrLinkQualityEvent;

// Energy Monitor BQR event
typedef struct {
  // Quality report ID.
  uint8_t quality_report_id;
  // Average current consumption of all activities consumed by the controller (mA)
  uint16_t avg_current_consume;
  // Total time in the idle (low power states, sleep) state. (ms)
  uint32_t idle_total_time;
  // Indicates how many times the controller enters the idle state.
  uint32_t idle_state_enter_count;
  // Total time in the active (inquiring, paging, ACL/SCO/eSCO/BIS/CIS traffic, processing any task)
  // state. (ms)
  uint32_t active_total_time;
  // Indicates how many times the controller enters the active states.
  uint32_t active_state_enter_count;
  // Total time in the BR/EDR specific Tx(Transmitting for ACL/SCO/eSCO traffic)state (ms)
  uint32_t bredr_tx_total_time;
  // Indicates how many times the controller enters the BR/EDR specific Tx state.
  uint32_t bredr_tx_state_enter_count;
  // Average Tx power level of all the BR/EDR link(s) (dBm)
  uint8_t bredr_tx_avg_power_lv;
  // Total time in the BR/EDR specific Rx (Receiving from ACL/SCO/eSCO traffic) state. (ms)
  uint32_t bredr_rx_total_time;
  // Indicates how many times the controller enters the BR/EDR specific Rx state. (ms)
  uint32_t bredr_rx_state_enter_count;
  // Total time in the LE specific Tx (Transmitting for either ACL/BIS/CIS or LE advertising
  // traffic) state (ms)
  uint32_t le_tx_total_time;
  // Indicates how many times the controller enters theLE specific Tx state.
  uint32_t le_tx_state_enter_count;
  // Average Tx power level of all the LE link(s) (dBm)
  uint8_t le_tx_avg_power_lv;
  // Total time in the LE specific Rx (Receiving from either ACL/BIS/CIS or LE scanning traffic)
  // state. (ms)
  uint32_t le_rx_total_time;
  // Indicates how many times the controller enters the LE specific Rx state
  uint32_t le_rx_state_enter_count;
  // The total time duration to collect power related information (ms)
  uint32_t tm_period;
  // The time duration of RX active in one chain
  uint32_t rx_active_one_chain_time;
  // The time duration of RX active in two chain
  uint32_t rx_active_two_chain_time;
  // The time duration of internal TX active in one chain
  uint32_t tx_ipa_active_one_chain_time;
  // The time duration of internal TX active in two chain
  uint32_t tx_ipa_active_two_chain_time;
  // The time duration of external TX active in one chain
  uint32_t tx_epa_active_one_chain_time;
  // The time duration of external TX active in two chain
  uint32_t tx_epa_active_two_chain_time;
} __attribute__((__packed__)) BqrEnergyMonitorEvent;

static constexpr uint8_t kEnergyMonitorParamTotalLen = sizeof(BqrEnergyMonitorEvent);

// RF Stats BQR event
typedef struct {
  // Quality report ID.
  uint8_t quality_report_id;
  // Extension for Further usage = 0x01 for BQRv6
  uint8_t ext_info;
  // time period (ms)
  uint32_t tm_period;
  // Packet counter of iPA BF
  uint32_t tx_pw_ipa_bf;
  // Packet counter of ePA BF
  uint32_t tx_pw_epa_bf;
  // Packet counter of iPA Div
  uint32_t tx_pw_ipa_div;
  // Packet counter of ePA Div
  uint32_t tx_pw_epa_div;
  // Packet counter of RSSI chain > -50 dBm
  uint32_t rssi_ch_50;
  // Packet counter of RSSI chain between  -50 dBm ~ >-55 dBm
  uint32_t rssi_ch_50_55;
  // Packet counter of RSSI chain between  -55 dBm ~ >-60 dBm
  uint32_t rssi_ch_55_60;
  // Packet counter of RSSI chain between  -60 dBm ~ >-65 dBm
  uint32_t rssi_ch_60_65;
  // Packet counter of RSSI chain between  -65 dBm ~ >-70 dBm
  uint32_t rssi_ch_65_70;
  // Packet counter of RSSI chain between  -70 dBm ~ >-75 dBm
  uint32_t rssi_ch_70_75;
  // Packet counter of RSSI chain between  -75 dBm ~ >-80 dBm
  uint32_t rssi_ch_75_80;
  // Packet counter of RSSI chain between  -80 dBm ~ >-85 dBm
  uint32_t rssi_ch_80_85;
  // Packet counter of RSSI chain between  -85 dBm ~ >-90 dBm
  uint32_t rssi_ch_85_90;
  // Packet counter of RSSI chain  < -90 dBm
  uint32_t rssi_ch_90;
  // Packet counter of RSSI delta < 2 dBm
  uint32_t rssi_delta_2_down;
  // Packet counter of  RSSI delta between 2 dBm ~ 5 dBm
  uint32_t rssi_delta_2_5;
  // Packet counter of  RSSI delta between 5 dBm ~ 8 dB
  uint32_t rssi_delta_5_8;
  // Packet counter of  RSSI delta between 8 dBm ~ 11 dBm
  uint32_t rssi_delta_8_11;
  // Packet counter of RSSI delta > 11 dBm
  uint32_t rssi_delta_11_up;
} __attribute__((__packed__)) BqrRFStatsEvent;

// Total length of all parameters of the RF Stats event
static constexpr uint8_t kRFStatsParamTotalLen = sizeof(BqrRFStatsEvent);

// Log dump related BQR event
typedef struct {
  // Quality report ID.
@@ -352,6 +460,20 @@ public:
  // @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.
  void ParseBqrLinkQualityEvt(uint8_t length, const uint8_t* p_param_buf);
  // Parse the Energy Monitor BQR 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 true if the event was parsed successfully, false otherwise.
  bool ParseBqrEnergyMonitorEvt(uint8_t length, const uint8_t* p_param_buf);
  // Parse the RF Stats BQR 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 true if the event was parsed successfully, false otherwise.
  bool ParseBqrRFStatsEvt(uint8_t length, const uint8_t* p_param_buf);
  // Write the LMP/LL message trace to the log file.
  //
  // @param fd The File Descriptor of the log file.
@@ -376,6 +498,10 @@ public:
  virtual ~BqrVseSubEvt() = default;
  // Link Quality related BQR event
  BqrLinkQualityEvent bqr_link_quality_event_ = {};
  // Energy Monitor BQR event
  BqrEnergyMonitorEvent bqr_energy_monitor_event_ = {};
  // RF Stats BQR event
  BqrRFStatsEvent bqr_rf_stats_event_ = {};
  // Log Dump related BQR event
  BqrLogDumpEvent bqr_log_dump_event_ = {};
  // Local wall clock timestamp of receiving BQR VSE sub-event
+158 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <fcntl.h>
#ifdef __ANDROID__
#include <statslog_bt.h>
@@ -148,6 +149,79 @@ void BqrVseSubEvt::ParseBqrLinkQualityEvt(uint8_t length, const uint8_t* p_param
  localtime_r(&now, &tm_timestamp_);
}

bool BqrVseSubEvt::ParseBqrEnergyMonitorEvt(uint8_t length, const uint8_t* p_param_buf) {
  if (length < kEnergyMonitorParamTotalLen) {
    log::fatal(
            "Parameter total length: {} is abnormal. It shall be not shorter than: "
            "{}",
            length, kEnergyMonitorParamTotalLen);
    return false;
  }

  STREAM_TO_UINT8(bqr_energy_monitor_event_.quality_report_id, p_param_buf);
  bqr_link_quality_event_.quality_report_id = bqr_energy_monitor_event_.quality_report_id;
  STREAM_TO_UINT16(bqr_energy_monitor_event_.avg_current_consume, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.idle_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.idle_state_enter_count, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.active_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.active_state_enter_count, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_tx_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_tx_state_enter_count, p_param_buf);
  STREAM_TO_UINT8(bqr_energy_monitor_event_.bredr_tx_avg_power_lv, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_rx_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_rx_state_enter_count, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.le_tx_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.le_tx_state_enter_count, p_param_buf);
  STREAM_TO_UINT8(bqr_energy_monitor_event_.le_tx_avg_power_lv, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.le_rx_total_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.le_rx_state_enter_count, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.tm_period, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.rx_active_one_chain_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.rx_active_two_chain_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_ipa_active_one_chain_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_ipa_active_two_chain_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_epa_active_one_chain_time, p_param_buf);
  STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_epa_active_two_chain_time, p_param_buf);
  return true;
}

bool BqrVseSubEvt::ParseBqrRFStatsEvt(uint8_t length, const uint8_t* p_param_buf) {
  if (length < kRFStatsParamTotalLen) {
    log::fatal(
            "Parameter total length: {} is abnormal. It shall be not shorter than: "
            "{}",
            length, kRFStatsParamTotalLen);
    return false;
  }

  STREAM_TO_UINT8(bqr_rf_stats_event_.quality_report_id, p_param_buf);
  bqr_link_quality_event_.quality_report_id = bqr_rf_stats_event_.quality_report_id;
  STREAM_TO_UINT8(bqr_rf_stats_event_.ext_info, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.tm_period, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_ipa_bf, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_epa_bf, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_ipa_div, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_epa_div, p_param_buf);

  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_50, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_50_55, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_55_60, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_60_65, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_65_70, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_70_75, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_75_80, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_80_85, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_85_90, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_90, p_param_buf);

  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_2_down, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_2_5, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_5_8, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_8_11, p_param_buf);
  STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_11_up, p_param_buf);
  return true;
}

void BqrVseSubEvt::WriteLmpLlTraceLogFile(int fd, uint8_t length, const uint8_t* p_param_buf) {
  const auto now = system_clock::to_time_t(system_clock::now());
  localtime_r(&now, &tm_timestamp_);
@@ -219,7 +293,19 @@ std::string BqrVseSubEvt::ToString() const {
       << ", CRCError: " << std::to_string(bqr_link_quality_event_.crc_error_packets)
       << ", RxDuplicate: " << std::to_string(bqr_link_quality_event_.rx_duplicate_packets);
  }

  if (QUALITY_REPORT_ID_ENERGY_MONITOR == bqr_link_quality_event_.quality_report_id) {
    ss << ", TotalTime: " << std::to_string(bqr_energy_monitor_event_.tm_period)
       << ", ActiveTime: " << std::to_string(bqr_energy_monitor_event_.active_total_time)
       << ", IdleTime: " << std::to_string(bqr_energy_monitor_event_.idle_total_time)
       << ", AvgCurrent: " << std::to_string(bqr_energy_monitor_event_.avg_current_consume);
  }
  if (QUALITY_REPORT_ID_RF_STATS == bqr_link_quality_event_.quality_report_id) {
    ss << ", TotalTime: " << std::to_string(bqr_rf_stats_event_.tm_period)
       << ", TxiPABF: " << std::to_string(bqr_rf_stats_event_.tx_pw_ipa_bf)
       << ", TxePABF: " << std::to_string(bqr_rf_stats_event_.tx_pw_epa_bf)
       << ", TxiPADiv: " << std::to_string(bqr_rf_stats_event_.tx_pw_ipa_div)
       << ", TxePADiv: " << std::to_string(bqr_rf_stats_event_.tx_pw_epa_div);
  }
  return ss.str();
}

@@ -241,6 +327,10 @@ static std::string QualityReportIdToString(uint8_t quality_report_id) {
      return "LE Audio Choppy";
    case QUALITY_REPORT_ID_CONNECT_FAIL:
      return "Connect Fail";
    case QUALITY_REPORT_ID_ENERGY_MONITOR:
      return "Energy Monitor";
    case QUALITY_REPORT_ID_RF_STATS:
      return "RF Stats";
    default:
      return "Invalid";
  }
@@ -570,6 +660,9 @@ static void ConfigureBqrCmpl(uint32_t current_evt_mask) {
  }
}

static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_quality_event);
static void AddEnergyMonitorEventToQueue(uint8_t length, const uint8_t* p_link_quality_event);
static void AddRFStatsEventToQueue(uint8_t length, const uint8_t* p_link_quality_event);
static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_quality_event);
// Categorize the incoming Bluetooth Quality Report.
//
@@ -613,6 +706,34 @@ static void CategorizeBqrEvent(uint8_t length, const uint8_t* p_bqr_event) {
      log::warn("Unexpected ID: 0x{:x}", quality_report_id);
      break;

    case QUALITY_REPORT_ID_ENERGY_MONITOR:
      if (length < kEnergyMonitorParamTotalLen) {
        log::fatal(
                "Parameter total length: {} is abnormal. It shall be not shorter "
                "than: {}",
                length, kEnergyMonitorParamTotalLen);
        return;
      }

      if (com::android::bluetooth::flags::support_bluetooth_quality_report_v6()) {
        AddEnergyMonitorEventToQueue(length, p_bqr_event);
      }
      break;

    case QUALITY_REPORT_ID_RF_STATS:
      if (length < kRFStatsParamTotalLen) {
        log::fatal(
                "Parameter total length: {} is abnormal. It shall be not shorter "
                "than: {}",
                length, kRFStatsParamTotalLen);
        return;
      }

      if (com::android::bluetooth::flags::support_bluetooth_quality_report_v6()) {
        AddRFStatsEventToQueue(length, p_bqr_event);
      }
      break;

    default:
      log::warn("Unknown ID: 0x{:x}", quality_report_id);
      break;
@@ -687,6 +808,42 @@ static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_qua
  kpBqrEventQueue.Enqueue(p_bqr_event.release());
}

static void AddEnergyMonitorEventToQueue(uint8_t length, const uint8_t* p_energy_monitor_event) {
  std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();

  if (!p_bqr_event->ParseBqrEnergyMonitorEvt(length, p_energy_monitor_event)) {
    log::warn("failed to parse BQR energy monitor event");
    return;
  }

  BluetoothQualityReportInterface* bqrItf = getBluetoothQualityReportInterface();

  if (bqrItf == NULL) {
    log::warn("failed to deliver BQR, bqrItf is NULL");
    return;
  }

  bqrItf->bqr_delivery_event(RawAddress::kAny, p_energy_monitor_event, length);
}

static void AddRFStatsEventToQueue(uint8_t length, const uint8_t* p_rf_stats_event) {
  std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();

  if (!p_bqr_event->ParseBqrRFStatsEvt(length, p_rf_stats_event)) {
    log::warn("failed to parse BQR RF stats event");
    return;
  }

  BluetoothQualityReportInterface* bqrItf = getBluetoothQualityReportInterface();

  if (bqrItf == NULL) {
    log::warn("failed to deliver BQR, bqrItf is NULL");
    return;
  }

  bqrItf->bqr_delivery_event(RawAddress::kAny, p_rf_stats_event, length);
}

static int OpenLmpLlTraceLogFile();

// Dump the LMP/LL message handshaking with the remote device to a log file.