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

Commit f276b177 authored by Barry Wang's avatar Barry Wang Committed by Gerrit Code Review
Browse files

Merge "Add BQRv6 parameter parser for upload to framework" into main

parents a9d110b7 91ae45af
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
@@ -200,8 +200,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,
@@ -330,6 +332,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.
@@ -348,6 +456,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.
@@ -372,6 +494,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>
@@ -155,6 +156,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_);
@@ -226,7 +300,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();
}

@@ -248,6 +334,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";
  }
@@ -588,6 +678,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.
//
@@ -631,6 +724,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;
@@ -705,6 +826,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.