code

#include "include/SubframeWorker.h"
#include "include/DCISearch.h"
#include "include/SubframeInfo.h"
#include "falcon/prof/Lifetime.h"

#include <iostream>

/* Buffers for PCH reception (not included in DL HARQ) */
const static uint32_t pch_payload_buffer_sz = 8 * 1024; // cf. srsran: srsue/hdr/mac/mac.h

SubframeWorker::SubframeWorker(uint32_t idx,
                               uint32_t max_prb,
                               PhyCommon &common,
                               DCIMetaFormats &metaFormats,
                               LTESniffer_pcap_writer *pcapwriter,
                               MCSTracking *mcs_tracking,
                               HARQ *harq,
                               int mcs_tracking_mode,
                               int harq_mode,
                               ULSchedule *ulsche,
                               int sniffer_mode) : sfb(common.nof_rx_antennas),
                                                   idx(idx),
                                                   max_prb(max_prb),
                                                   common(common),
                                                   metaFormats(metaFormats),
                                                   sf_idx(0),
                                                   sfn(0),
                                                   updateMetaFormats(false),
                                                   stats(),
                                                   pcapwriter(pcapwriter),
                                                   mcs_tracking(mcs_tracking),
                                                   harq(harq),
                                                   harq_mode(harq_mode),
                                                   mcs_tracking_mode(mcs_tracking_mode),
                                                   ulsche(ulsche),
                                                   pdschdecoder(),
                                                   puschdecoder(),
                                                   sniffer_mode(sniffer_mode),
                                                   filesink(),
                                                   est_cfo(mcs_tracking->get_est_cfo())
{
  /*Set UE-specific config for UL and DL Decoder, correct value will be set after sniffer decodes RRC Connection Setup*/
  set_ue_dl_uecfg(&ue_dl_cfg);
  set_pdsch_uecfg(&ue_dl_cfg.cfg.pdsch);
  /*Create new ue_dl*/
  falcon_ue_dl.q = new srsran_ue_dl_t;

  switch (sniffer_mode)
  {
  case DL_MODE:
    /* Config for Downlink Sniffing function*/
    srsran_ue_dl_init(falcon_ue_dl.q, sfb.sf_buffer, max_prb, common.nof_rx_antennas);
    /* PDSCH decoder (Downlink)*/
    pdschdecoder = new PDSCH_Decoder(idx, pcapwriter, mcs_tracking, common.getRNTIManager(), harq, mcs_tracking_mode, harq_mode, common.nof_rx_antennas);
    break;
  case UL_MODE:
    /* Config for Downlink Sniffing function*/
    srsran_ue_dl_init(falcon_ue_dl.q, sfb.sf_buffer, max_prb, 1); // only 1 antenna for DL in the UL Sniffer Mode
    /* PDSCH decoder (Downlink)*/
    pdschdecoder = new PDSCH_Decoder(idx,
                                     pcapwriter,
                                     mcs_tracking,
                                     common.getRNTIManager(),
                                     harq,
                                     mcs_tracking_mode,
                                     harq_mode,
                                     common.nof_rx_antennas);
    /* PUSCH decoder (Uplink)*/
    puschdecoder = new PUSCH_Decoder(enb_ul,
                                     ul_sf,
                                     ulsche,
                                     sfb.sf_buffer,
                                     sfb.sf_buffer_offset,
                                     ul_cfg,
                                     pcapwriter,
                                     mcs_tracking,
                                     mcs_tracking->get_debug_mode());
    /*Uplink enb init*/
    if (srsran_enb_ul_init(&enb_ul, sfb.sf_buffer[1], 110))
    { // 110 = max PRB
      ERROR("Error initiating ENB UL");
      return;
    }
    break;
  default:
    break;
  }
  /*Init filesink for saving IQ samples in test mode*/
  srsran_filesink_init(&filesink, "ul_sample.raw", SRSRAN_COMPLEX_FLOAT_BIN);
}

SubframeWorker::~SubframeWorker()
{
  srsran_ue_dl_free(falcon_ue_dl.q);
  delete pdschdecoder;
  pdschdecoder = nullptr;
  srsran_filesink_free(&filesink);
}

bool SubframeWorker::setCell(srsran_cell_t cell)
{
  if (srsran_ue_dl_set_cell(falcon_ue_dl.q, cell))
  {
    return false;
  }
  return true;
}

void SubframeWorker::prepare(uint32_t _sf_idx, uint32_t _sfn, bool updateMetaFormats,
                             srsran_dl_sf_cfg_t _dl_sf)
{
  this->sf_idx = _sf_idx;
  this->sfn = _sfn;
  this->updateMetaFormats = updateMetaFormats;
  dl_sf = _dl_sf;
}

uint16_t get_tti_ul_harq(uint16_t cur_tti)
{
  uint32_t temp_tti = cur_tti - 4;
  if (temp_tti >= 0)
  {
    return temp_tti;
  }
  else
  {
    temp_tti = temp_tti + 10240;
    return temp_tti;
  }
}

// int update_rv(int old_rv){
// if (old_rv == 0){
// return 2;
// } else if (old_rv == 2){
// return 3;
// } else if (old_rv == 3){
// return 1;
// }
// }

void SubframeWorker::work()
{
    std::string test_string = '[' + std::to_string(idx) + ']' + '[' + std::to_string(sfn) + '-' + std::to_string(sf_idx) + ']';
    // PrintLifetime worker_lifetime(test_string + " Subframe took: ");
    uint32_t tti = sfn * 10 + sf_idx;
    ul_sf.tti = tti;
    if (updateMetaFormats)
    {
        metaFormats.update_formats();
    }

    SubframeInfo subframeInfo(falcon_ue_dl.q->cell, // contain Subframe power and DCI collection only
                            mcs_tracking_mode,
                            mcs_tracking,
                            harq_mode,
                            harq,
                            ulsche);
    DCISearch dciSearch(falcon_ue_dl,
                      metaFormats,
                      common.getRNTIManager(),
                      subframeInfo,
                      sf_idx, sfn,
                      &dl_sf, &ue_dl_cfg);
    dciSearch.setShortcutDiscovery(common.getShortcutDiscovery());

    int snr_ret = SRSRAN_SUCCESS;

    // Added code to obtain UL and DL DCI lists
    std::vector<DCI_UL> dci_ul = subframeInfo.getDCICollection().getULSnifferDCI_UL(); // Get UL DCI list
    std::vector<DL_Sniffer_DCI_DL> dci_dl = subframeInfo.getDCICollection().getDLSnifferDCI_DL(); // Get DL DCI list

    switch (sniffer_mode)
    {
    case DL_MODE:
        snr_ret = dciSearch.search();
        if (snr_ret == SRSRAN_SUCCESS)
        {
            stats += dciSearch.getStats();
            common.addStats(dciSearch.getStats());
            run_dl_mode(subframeInfo);
        }
        else
        {
            // printf("[SIGNAL] Bad signal quality... \n");
        }
        break;
    case UL_MODE:
        dciSearch.prepareDCISearch();
        snr_ret = dciSearch.search();
        if (snr_ret == SRSRAN_SUCCESS)
        {
            stats += dciSearch.getStats();
            common.addStats(dciSearch.getStats());
            subframeInfo.getSubframePower().computePower(enb_ul.sf_symbols);
            run_ul_mode(subframeInfo, tti);
        }
        else
        {
            // printf("[SIGNAL] Bad signal quality... \n");
        }
        break;
    default:
        break;
    }
    /*Update CFO for ue_sync in sync thread*/
    est_cfo = falcon_ue_dl.q->chest_res.cfo;
    falcon_ue_dl.q->chest_res.cfo = 0;
    // common.consumeDCICollection(subframeInfo); //save DCI to file
    // print_nof_DCI(subframeInfo, tti);
}
void SubframeWorker::printStats()
{
  stats.print(common.getStatsFile());
}

DCIBlindSearchStats &SubframeWorker::getStats()
{
  return stats;
}

cf_t *SubframeWorker::getBuffer(uint32_t antenna_idx)
{
  return sfb.sf_buffer[antenna_idx];
}

void SubframeWorker::run_dl_mode(SubframeInfo &subframeInfo)
{
  pdschdecoder->init_pdsch_decoder(&falcon_ue_dl,
                                   &dl_sf,
                                   &ue_dl_cfg,
                                   &subframeInfo.getDCICollection().getDLSnifferDCI_DL(),
                                   sfn,
                                   sf_idx);
  /*Start decoding PDSCH*/
  pdschdecoder->decode_dl_mode();
}

void SubframeWorker::run_ul_mode(SubframeInfo &subframeInfo, uint32_t tti)
{
  if (!ulsche->get_config())
  {
    int sib_ret = SRSRAN_SUCCESS;
    pdschdecoder->init_pdsch_decoder(&falcon_ue_dl,
                                     &dl_sf,
                                     &ue_dl_cfg,
                                     &subframeInfo.getDCICollection().getDLSnifferDCI_DL(),
                                     sfn,
                                     sf_idx);
    sib_ret = pdschdecoder->decode_SIB();
    if (sib_ret == DL_SNIFFER_SIB2_SUCCESS)
    {
      ulsche->set_SIB2(pdschdecoder->getSIB2());
      ulsche->set_config();
    }
  }
  else
  {
    // decode uplink pusch
    if (config == false)
    {
      ul_cfg.dmrs = ulsche->get_dmrs();
      ;
      if (srsran_enb_ul_set_cell(&enb_ul, falcon_ue_dl.q->cell, &ul_cfg.dmrs, nullptr))
      {
        ERROR("Error set cell ENB UL");
        return;
      }
      set_config();

      // init PUSCH decoder
      // ul_cfg.hopping.hopping_enabled = true;
      ul_cfg.hopping.hop_mode = srsran_pusch_hopping_cfg_t::SRSRAN_PUSCH_HOP_MODE_INTER_SF;
      ul_cfg.hopping.hopping_offset = ulsche->sib2.rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset;
      ul_cfg.hopping.n_sb = ulsche->sib2.rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.n_sb;
      ul_cfg.hopping.n_rb_ho = ulsche->sib2.rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset;
      ;

      /*RAR decode hopping config to convert dci 0 to ul grant*/
      pdschdecoder->set_hopping(ul_cfg.hopping);

      /*RACH detector config*/
      puschdecoder->set_rach_config(ulsche->get_prach_config());
      puschdecoder->set_configed();
    }
    if (puschdecoder->get_configed())
    {
      /*Decode DL messages but only TM1 as only having 1 antenna for DL*/
      pdschdecoder->init_pdsch_decoder(&falcon_ue_dl,
                                       &dl_sf,
                                       &ue_dl_cfg,
                                       &subframeInfo.getDCICollection().getDLSnifferDCI_DL(),
                                       sfn,
                                       sf_idx);

      /*Create a vector to contain RAR decoding result*/
      std::vector<DL_Sniffer_rar_result> rar_result;
      int ret = pdschdecoder->decode_ul_mode(ulsche->get_rnti(), &rar_result);

      /*Get Uplink and Downlink dci and grant lists*/
      std::vector<DCI_UL> dci_ul = subframeInfo.getDCICollection().getULSnifferDCI_UL(); // get UL DCI0 list
      std::vector<DL_Sniffer_DCI_DL> dci_dl = subframeInfo.getDCICollection().getDLSnifferDCI_DL(); // get DL DCI list
      
      /*UL grant for RRC Connection Request is sent in RAR response (msg 2),
      / so convert UL grant from msg2 to general UL grant*/
      std::vector<DCI_UL> rar_dci_ul_vector;
      if (rar_result.size() > 0)
      {
        std::vector<DL_Sniffer_rar_result>::iterator rar_iter;
        for (rar_iter = rar_result.begin(); rar_iter != rar_result.end(); rar_iter++)
        {
          DCI_UL rar_dci_ul = {};
          rar_dci_ul.rnti = (*rar_iter).t_crnti;
          *rar_dci_ul.ran_ul_dci.get() = (*rar_iter).ran_dci_ul;
          *rar_dci_ul.ran_ul_grant.get() = (*rar_iter).ran_ul_grant;
          rar_dci_ul.is_rar_gant = 1;
          rar_dci_ul_vector.push_back(rar_dci_ul);
        }
      }

      /*check nof_ack for uplink pusch decoder*/
      std::vector<DCI_UL>::iterator iter_ul;
      std::vector<DL_Sniffer_DCI_DL>::iterator iter_dl;
      for (iter_ul = dci_ul.begin(); iter_ul != dci_ul.end(); iter_ul++)
      {
        for (iter_dl = dci_dl.begin(); iter_dl != dci_dl.end(); iter_dl++)
        {
          if (iter_ul->rnti == iter_dl->rnti)
          {
            if (iter_dl->ran_pdsch_grant->nof_tb == 1)
            {
              iter_ul->nof_ack = 1;
            }
            else if (iter_dl->ran_pdsch_grant->nof_tb == 2)
            {
              iter_ul->nof_ack = 2;
            }
          }
        }
      }

      /*Push current UL DCI0 to database to decode 4ms later*/
      ulsche->pushULSche(tti, dci_ul);
      /*Push current RAR grant to database to decode 4ms later*/
      ulsche->push_rar_ULSche(tti, rar_dci_ul_vector);
      puschdecoder->init_pusch_decoder(ulsche->getULSche(tti),
                                       ulsche->get_rar_ULSche(tti),
                                       ul_sf,
                                       &subframeInfo.getSubframePower());
      puschdecoder->decode(); // decode PUSCH
      puschdecoder->work_prach(); // decode PRACH
      ulsche->deleteULSche(tti); // delete current DCI0 list and uplink grant in the database after decoding
      ulsche->delete_rar_ULSche(tti); // also for RAR grant
    }
  }
}
void SubframeWorker::setup_default_ul_cfg(srsran_ul_cfg_t &ul_cfg)
{

  ul_cfg.pusch.uci_offset.I_offset_ack = 10;
  ul_cfg.pusch.uci_offset.I_offset_cqi = 8;
  ul_cfg.pusch.uci_offset.I_offset_ri = 11;
}

void SubframeWorker::set_pdsch_uecfg(srsran_pdsch_cfg_t *pdsch_cfg)
{
  pdsch_cfg->csi_enable = true;
  pdsch_cfg->max_nof_iterations = 12;
  pdsch_cfg->meas_evm_en = false;
  pdsch_cfg->meas_time_en = false;
  pdsch_cfg->power_scale = true;
  pdsch_cfg->decoder_type = SRSRAN_MIMO_DECODER_MMSE;
  pdsch_cfg->p_a = -3;

  pdsch_cfg->p_b = 1;
  pdsch_cfg->rs_power = 0;
}

void SubframeWorker::set_ue_dl_uecfg(srsran_ue_dl_cfg_t *ue_dl_cfg)
{
  /*Set config for channel estimation*/
  srsran_chest_dl_cfg_t *chest_cfg = &ue_dl_cfg->chest_cfg;
  bzero(chest_cfg, sizeof(srsran_chest_dl_cfg_t));
  chest_cfg->filter_coef[0] = 4;
  chest_cfg->filter_coef[1] = 1;
  chest_cfg->filter_type = SRSRAN_CHEST_FILTER_GAUSS;
  chest_cfg->noise_alg = SRSRAN_NOISE_ALG_REFS;
  chest_cfg->rsrp_neighbour = false;
  chest_cfg->cfo_estimate_enable = true;
  chest_cfg->cfo_estimate_sf_mask = 1023;
  chest_cfg->sync_error_enable = false;
  chest_cfg->estimator_alg = SRSRAN_ESTIMATOR_ALG_INTERPOLATE; // Change channel estimation algorithm
                                                               // SRSRAN_ESTIMATOR_ALG_WIENER = 2
                                                               // SRSRAN_ESTIMATOR_ALG_INTERPOLATE = 1
                                                               // SRSRAN_ESTIMATOR_ALG_AVERAGE = 0
  /*Set config for DCI search, can config DCI for CA cases*/
  ue_dl_cfg->cfg.dci.multiple_csi_request_enabled = false;
  ue_dl_cfg->cfg.dci.cif_enabled = false;
  ue_dl_cfg->cfg.dci.cif_present = false;
  ue_dl_cfg->cfg.dci.is_not_ue_ss = false;
  ue_dl_cfg->cfg.dci.ra_format_enabled = false;
  ue_dl_cfg->cfg.dci.srs_request_enabled = false;
}

void SubframeWorker::print_nof_DCI(SubframeInfo &subframeInfo, uint32_t tti)
{
  std::vector<DL_Sniffer_DCI_DL> dl_dci_test = subframeInfo.getDCICollection().getDLSnifferDCI_DL();
  int nof_dl_dci = dl_dci_test.size();
  std::vector<DCI_UL> dci_ul_test = subframeInfo.getDCICollection().getULSnifferDCI_UL();
  int nof_ul_dci = dci_ul_test.size();
  auto now = std::chrono::system_clock::now();
  auto micros = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch());
  int nof_dci = nof_dl_dci + nof_ul_dci;
  // Convert time to string in desired format
  auto time = std::chrono::system_clock::to_time_t(now);
  std::stringstream ss;
  ss << std::put_time(std::localtime(&time), "%H:%M:%S.")
     << std::setw(6) << std::setfill('0') << micros.count() % 1000000;
  std::string time_str = ss.str();

  std::cout << time_str << "," << tti << "," << nof_dci << std::endl;
}