OBECA Receive Process
Public Member Functions | List of all members
MbsfnFrameProcessor Class Reference

Frame processor for MBSFN subframes. More...

#include <MbsfnFrameProcessor.h>

Public Member Functions

 MbsfnFrameProcessor (const libconfig::Config &cfg, srslte::rlc &rlc, Phy &phy, srslte::log_ref log_h, RestHandler &rest)
 Default constructor. More...
 
virtual ~MbsfnFrameProcessor ()
 Default destructor.
 
bool init ()
 Initialize signal- and softbuffers, init all underlying components. More...
 
int process (uint32_t tti)
 Process the sample data in the signal buffer. More...
 
void set_cell (srslte_cell_t cell)
 Set the parameters for the cell (Nof PRB, etc). More...
 
cf_t ** get_rx_buffer_and_lock ()
 Get a handle of the signal buffer to store samples for processing in, and lock this processor. More...
 
uint32_t rx_buffer_size ()
 Size of the signal buffer.
 
void configure_mbsfn (uint8_t area_id, srslte_scs_t subcarrier_spacing)
 Set MBSFN parameters: area ID and subcarrier spacing.
 
bool mbsfn_configured ()
 Returns tru if MBSFN params have already been configured.
 
void unlock ()
 Unlock the processor. More...
 
const std::vector< uint8_t > mch_data () const
 Get the constellation diagram data (I/Q data of the subcarriers after CE)
 
float cinr_db ()
 Get the CINR estimate (in dB)
 

Detailed Description

Frame processor for MBSFN subframes.

Handles the complete processing chain for a CAS subframe: calls FFT and channel estimation, decodes PDSCH and passes received PDUs to RLC.

Definition at line 39 of file MbsfnFrameProcessor.h.

Constructor & Destructor Documentation

◆ MbsfnFrameProcessor()

MbsfnFrameProcessor::MbsfnFrameProcessor ( const libconfig::Config &  cfg,
srslte::rlc &  rlc,
Phy &  phy,
srslte::log_ref  log_h,
RestHandler &  rest 
)
inline

Default constructor.

Parameters
cfgConfig singleton reference
phyPHY reference
rlcRLC reference
log_hsrsLTE log handle for the MCH MAC msg decoder
restRESTful API handler reference

Definition at line 50 of file MbsfnFrameProcessor.h.

51  : _cfg(cfg)
52  , _rlc(rlc)
53  , _phy(phy)
54  , _rest(rest)
55  , mch_mac_msg(20, log_h) {}

Member Function Documentation

◆ get_rx_buffer_and_lock()

cf_t** MbsfnFrameProcessor::get_rx_buffer_and_lock ( )
inline

Get a handle of the signal buffer to store samples for processing in, and lock this processor.

The processor unlocks itself after (failed or successful) frame processing in process(). If process() is not called by the application after calling this method, it must unlock the processor itself by calling unlock()

Definition at line 91 of file MbsfnFrameProcessor.h.

91 { _mutex.lock(); return _signal_buffer_rx; }

◆ init()

auto MbsfnFrameProcessor::init ( )

Initialize signal- and softbuffers, init all underlying components.

Must be called once before the first call to process().

Definition at line 29 of file MbsfnFrameProcessor.cpp.

29  {
30  _signal_buffer_max_samples = 3 * SRSLTE_SF_LEN_PRB(MAX_PRB);
31 
32  _signal_buffer_rx[0] = srslte_vec_cf_malloc(_signal_buffer_max_samples);
33  if (_signal_buffer_rx[0] == nullptr) {
34  spdlog::error("Could not allocate regular DL signal buffer\n");
35  return false;
36  }
37 
38  if (srslte_ue_dl_init(&_ue_dl, _signal_buffer_rx, MAX_PRB, 1) != 0) {
39  spdlog::error("Could not init ue_dl\n");
40  return false;;
41  }
42 
43  srslte_softbuffer_rx_init(&_softbuffer, 100);
44 
45  _ue_dl_cfg.snr_to_cqi_offset = 0;
46 
47  srslte_chest_dl_cfg_t* chest_cfg = &_ue_dl_cfg.chest_cfg;
48  bzero(chest_cfg, sizeof(srslte_chest_dl_cfg_t));
49  chest_cfg->filter_coef[0] = 0.1;
50  chest_cfg->filter_type = SRSLTE_CHEST_FILTER_TRIANGLE;
51  chest_cfg->noise_alg = SRSLTE_NOISE_ALG_EMPTY;
52  chest_cfg->rsrp_neighbour = false;
53  chest_cfg->sync_error_enable = false;
54  chest_cfg->estimator_alg = SRSLTE_ESTIMATOR_ALG_INTERPOLATE;
55  chest_cfg->cfo_estimate_enable = false;
56 
57  _ue_dl_cfg.cfg.pdsch.csi_enable = true;
58  _ue_dl_cfg.cfg.pdsch.max_nof_iterations = 8;
59  _ue_dl_cfg.cfg.pdsch.meas_evm_en = false;
60  _ue_dl_cfg.cfg.pdsch.decoder_type = SRSLTE_MIMO_DECODER_MMSE;
61  _ue_dl_cfg.cfg.pdsch.softbuffers.rx[0] = &_softbuffer;
62 
63  _pmch_cfg.pdsch_cfg.csi_enable = true;
64  _pmch_cfg.pdsch_cfg.max_nof_iterations = 8;
65  _pmch_cfg.pdsch_cfg.meas_evm_en = false;
66  _pmch_cfg.pdsch_cfg.decoder_type = SRSLTE_MIMO_DECODER_MMSE;
67 
68  _sf_cfg.sf_type = SRSLTE_SF_MBSFN;
69  return true;
70 }

◆ process()

auto MbsfnFrameProcessor::process ( uint32_t  tti)

Process the sample data in the signal buffer.

Data must already be present in the buffer obtained through the handle returnd by rx_buffer()

Parameters
ttiTTI of the subframe the data belongs to

Definition at line 82 of file MbsfnFrameProcessor.cpp.

82  {
83  spdlog::trace("Processing MBSFN TTI {}", tti);
84 
85  uint32_t sfn = tti / 10;
86  uint8_t sf = tti % 10;
87 
88  unsigned area = 0;
89  _sf_cfg.tti = tti;
90  _pmch_cfg.area_id = _area_id;
91  srslte_mbsfn_cfg_t mbsfn_cfg = _phy.mbsfn_config_for_tti(tti, area);
92  _ue_dl_cfg.chest_cfg.mbsfn_area_id = _area_id;
93 
94  if (sfn%50 == 0) {
95  if (mbsfn_cfg.is_mcch) {
96  _rest._mcch.errors = 0;
97  _rest._mcch.total = 1;
98  } else {
99  _rest._mch[area].errors = 0;
100  _rest._mch[area].total = 1;
101  }
102  }
103 
104  if (!mbsfn_cfg.enable) {
105  _mutex.unlock();
106  return -1;
107  }
108 
109  if (mbsfn_cfg.is_mcch) {
110  _rest._mcch.total++;
111  } else {
112  _rest._mch[area].total++;
113  }
114 
115  if (srslte_ue_dl_decode_fft_estimate(&_ue_dl, &_sf_cfg, &_ue_dl_cfg) < 0) {
116  if (mbsfn_cfg.is_mcch) {
117  _rest._mcch.errors++;
118  } else {
119  _rest._mch[area].errors++;
120  }
121  spdlog::error("Getting PDCCH FFT estimate");
122  _mutex.unlock();
123  return -1;
124  }
125 
126  srslte_configure_pmch(&_pmch_cfg, &_cell, &mbsfn_cfg);
127  srslte_ra_dl_compute_nof_re(&_cell, &_sf_cfg, &_pmch_cfg.pdsch_cfg.grant);
128 
129  _pmch_cfg.area_id = _area_id;
130 
131  srslte_softbuffer_rx_reset_cb(&_softbuffer, 1);
132 
133  srslte_pdsch_res_t pmch_dec = {};
134  _pmch_cfg.pdsch_cfg.softbuffers.rx[0] = &_softbuffer;
135  pmch_dec.payload = _payload_buffer;
136  srslte_softbuffer_rx_reset_tbs(_pmch_cfg.pdsch_cfg.softbuffers.rx[0], _pmch_cfg.pdsch_cfg.grant.tb[0].tbs);
137 
138  if (srslte_ue_dl_decode_pmch(&_ue_dl, &_sf_cfg, &_pmch_cfg, &pmch_dec) != 0) {
139  if (mbsfn_cfg.is_mcch) {
140  _rest._mcch.errors++;
141  } else {
142  _rest._mch[area].errors++;
143  }
144  spdlog::warn("Error decoding PMCH");
145  _mutex.unlock();
146  return -1;
147  }
148 
149  spdlog::trace("PMCH: tti: {}, l_crb={}, tbs={}, mcs={}, crc={}, snr={} dB, n_iter={}\n",
150  tti,
151  _pmch_cfg.pdsch_cfg.grant.nof_prb,
152  _pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8,
153  _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx,
154  pmch_dec.crc ? "OK" : "KO",
155  _ue_dl.chest_res.snr_db,
156  pmch_dec.avg_iterations_block);
157 
158  if (mbsfn_cfg.is_mcch) {
159  _rest._mcch.SetData(mch_data());
160  _rest._mcch.mcs = _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx;
161  _rest._mcch.ber = _softbuffer.ber;
162  } else {
163  _rest._mch[area].SetData(mch_data());
164  _rest._mch[area].mcs = _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx;
165  _rest._mch[area].present = true;
166  _rest._mch[area].ber = _softbuffer.ber;
167  }
168 
169  if (pmch_dec.crc) {
170  mch_mac_msg.init_rx(
171  static_cast<uint32_t>(_pmch_cfg.pdsch_cfg.grant.tb[0].tbs) / 8);
172  mch_mac_msg.parse_packet(_payload_buffer);
173 
174  while (mch_mac_msg.next()) {
175  if (srslte::mch_lcid::MCH_SCHED_INFO == mch_mac_msg.get()->mch_ce_type()) {
176  uint16_t stop = 0;
177  uint8_t lcid = 0;
178  while (mch_mac_msg.get()->get_next_mch_sched_info(&lcid, &stop)) {
179  const std::lock_guard<std::mutex> lock(_sched_stop_mutex);
180  spdlog::debug("Scheduling stop for LCID {} in sf {}", lcid, stop);
181  _sched_stops[ lcid ] = stop;
182  }
183  } else if (mch_mac_msg.get()->is_sdu()) {
184  uint32_t lcid = mch_mac_msg.get()->get_sdu_lcid();
185  spdlog::trace("Processing MAC MCH PDU entered, lcid {}", lcid);
186 
187  if (lcid >= SRSLTE_N_MCH_LCIDS) {
188  spdlog::warn("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_MCH_LCIDS, lcid);
189  if (mbsfn_cfg.is_mcch) {
190  _rest._mcch.errors++;
191  } else {
192  _rest._mch[area].errors++;
193  }
194  _mutex.unlock();
195  return -1;
196  }
197 
198  {
199  const std::lock_guard<std::mutex> lock(_rlc_mutex);
200  _phy._mcs = mbsfn_cfg.mbsfn_mcs;
201  _rlc.write_pdu_mch(lcid, mch_mac_msg.get()->get_sdu_ptr(), mch_mac_msg.get()->get_payload_size());
202  }
203  }
204  }
205  } else {
206  if (mbsfn_cfg.is_mcch) {
207  _rest._mcch.errors++;
208  } else {
209  _rest._mch[area].errors++;
210  }
211 
212  spdlog::warn("PMCH in TTI {} failed with CRC error", tti);
213  _mutex.unlock();
214  return -1;
215  }
216 
217  if (!mbsfn_cfg.is_mcch) {
218  for (uint32_t i = 0; i < _phy.mcch().nof_pmch_info; i++) {
219  unsigned fn_in_scheduling_period = sfn % srslte::enum_to_number(_phy.mcch().pmch_info_list[i].mch_sched_period);
220  unsigned sf_idx = fn_in_scheduling_period * 10 + sf - (fn_in_scheduling_period / 4) - 1;
221 
222  const std::lock_guard<std::mutex> lock(_sched_stop_mutex);
223  for (auto itr = _sched_stops.cbegin() ; itr != _sched_stops.cend() ;) {
224  if ( sf_idx >= itr->second ) {
225  const std::lock_guard<std::mutex> lock(_rlc_mutex);
226  spdlog::debug("Stopping LCID {} in tti {} (idx in rf {})", itr->first, tti, sf_idx);
227  _rlc.stop_mch(itr->first);
228  itr = _sched_stops.erase(itr);
229  } else {
230  itr = std::next(itr);
231  }
232  }
233  }
234  } else {
235  _rest._mcch.present = true;
236  }
237  _mutex.unlock();
238  return mbsfn_cfg.is_mcch ? 0 : 1;
239 }

◆ set_cell()

void MbsfnFrameProcessor::set_cell ( srslte_cell_t  cell)

Set the parameters for the cell (Nof PRB, etc).

Parameters
cellThe cell we're camping on

Definition at line 77 of file MbsfnFrameProcessor.cpp.

77  {
78  _cell = cell;
79  srslte_ue_dl_set_cell(&_ue_dl, cell);
80 }

◆ unlock()

void MbsfnFrameProcessor::unlock ( )
inline

Unlock the processor.

See also
get_rx_buffer_and_lock()

Definition at line 113 of file MbsfnFrameProcessor.h.

113 { _mutex.unlock(); }

The documentation for this class was generated from the following files:
MbsfnFrameProcessor::mch_data
const std::vector< uint8_t > mch_data() const
Get the constellation diagram data (I/Q data of the subcarriers after CE)
Definition: MbsfnFrameProcessor.cpp:249
Phy::mbsfn_config_for_tti
srslte_mbsfn_cfg_t mbsfn_config_for_tti(uint32_t tti, unsigned &area)
Returns the MBSFN configuration (MCS, etc) for the subframe with the passed TTI.
Definition: Phy.cpp:256
RestHandler::_mch
std::map< uint32_t, ChannelInfo > _mch
RX info for MCHs.
Definition: RestHandler.h:111
RestHandler::_mcch
ChannelInfo _mcch
RX info for MCCH.
Definition: RestHandler.h:106