5G-MAG Reference Tools - MBMS Modem
Public Member Functions | Private Attributes | Static Private Attributes | List of all members
MbsfnFrameProcessor Class Reference

Frame processor for MBSFN subframes. More...

#include <MbsfnFrameProcessor.h>

Collaboration diagram for MbsfnFrameProcessor:
Collaboration graph

Public Member Functions

 MbsfnFrameProcessor (const libconfig::Config &cfg, srsran::rlc &rlc, Phy &phy, srslog::basic_logger &log_h, RestHandler &rest, unsigned rx_channels)
 Default constructor. More...
 
virtual ~MbsfnFrameProcessor ()
 Default destructor. More...
 
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 (srsran_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. More...
 
void configure_mbsfn (uint8_t area_id, srsran_scs_t subcarrier_spacing)
 Set MBSFN parameters: area ID and subcarrier spacing. More...
 
bool mbsfn_configured ()
 Returns tru if MBSFN params have already been configured. More...
 
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) More...
 
float cinr_db ()
 Get the CINR estimate (in dB) More...
 

Private Attributes

const libconfig::Config & _cfg
 
srsran::rlc & _rlc
 
Phy_phy
 
srsran_cell_t _cell
 
cf_t * _signal_buffer_rx [SRSRAN_MAX_PORTS] = {}
 
uint32_t _signal_buffer_max_samples = 0
 
uint8_t _payload_buffer [_payload_buffer_sz]
 
srsran_softbuffer_rx_t _softbuffer
 
srsran_ue_dl_t _ue_dl = {}
 
srsran_ue_dl_cfg_t _ue_dl_cfg = {}
 
srsran_dl_sf_cfg_t _sf_cfg = {}
 
srsran_pmch_cfg_t _pmch_cfg = {}
 
uint8_t _area_id = 1
 
bool _mbsfn_configured = false
 
srsran::mch_pdu mch_mac_msg
 
std::mutex _mutex
 
RestHandler_rest
 
unsigned _rx_channels
 

Static Private Attributes

static const uint32_t _payload_buffer_sz = SRSRAN_MAX_BUFFER_SIZE_BYTES
 
static std::mutex _sched_stop_mutex
 
static std::map< uint8_t, uint16_t > _sched_stops
 
static std::mutex _rlc_mutex
 
static int _current_mcs
 

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,
srsran::rlc &  rlc,
Phy phy,
srslog::basic_logger &  log_h,
RestHandler rest,
unsigned  rx_channels 
)
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)
56  , _rx_channels(rx_channels)
57  {}
srsran::mch_pdu mch_mac_msg
const libconfig::Config & _cfg
static Config cfg
Global configuration object.
Definition: main.cpp:165

◆ ~MbsfnFrameProcessor()

MbsfnFrameProcessor::~MbsfnFrameProcessor ( )
virtual

Default destructor.

Definition at line 73 of file MbsfnFrameProcessor.cpp.

73  {
74  srsran_softbuffer_rx_free(&_softbuffer);
75  srsran_ue_dl_free(&_ue_dl);
76 }
srsran_softbuffer_rx_t _softbuffer

Member Function Documentation

◆ cinr_db()

float MbsfnFrameProcessor::cinr_db ( )
inline

Get the CINR estimate (in dB)

Definition at line 125 of file MbsfnFrameProcessor.h.

125 { return _ue_dl.chest_res.snr_db; }

◆ configure_mbsfn()

void MbsfnFrameProcessor::configure_mbsfn ( uint8_t  area_id,
srsran_scs_t  subcarrier_spacing 
)

Set MBSFN parameters: area ID and subcarrier spacing.

Definition at line 253 of file MbsfnFrameProcessor.cpp.

253  {
254  _sf_cfg.subcarrier_spacing = subcarrier_spacing;
255  srsran_ue_dl_set_mbsfn_subcarrier_spacing(&_ue_dl, subcarrier_spacing);
256 
257 
258  srsran_ue_dl_set_mbsfn_area_id(&_ue_dl, area_id);
259  _area_id = area_id;
260  _mbsfn_configured = true;
261 }
srsran_dl_sf_cfg_t _sf_cfg

◆ 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 93 of file MbsfnFrameProcessor.h.

93 { _mutex.lock(); return _signal_buffer_rx; }
cf_t * _signal_buffer_rx[SRSRAN_MAX_PORTS]

◆ 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 28 of file MbsfnFrameProcessor.cpp.

28  {
29  _signal_buffer_max_samples = 3 * SRSRAN_SF_LEN_PRB(MAX_PRB);
30 
31  for (auto ch = 0; ch < _rx_channels; ch++) {
32  _signal_buffer_rx[ch] = srsran_vec_cf_malloc(_signal_buffer_max_samples);
33  if (!_signal_buffer_rx[ch]) {
34  spdlog::error("Could not allocate regular DL signal buffer\n");
35  return false;
36  }
37  }
38 
39  if (srsran_ue_dl_init(&_ue_dl, _signal_buffer_rx, MAX_PRB, _rx_channels) != 0) {
40  spdlog::error("Could not init ue_dl\n");
41  return false;;
42  }
43 
44  srsran_softbuffer_rx_init(&_softbuffer, 100);
45 
46  _ue_dl_cfg.snr_to_cqi_offset = 0;
47 
48  srsran_chest_dl_cfg_t* chest_cfg = &_ue_dl_cfg.chest_cfg;
49  bzero(chest_cfg, sizeof(srsran_chest_dl_cfg_t));
50  chest_cfg->filter_coef[0] = 0.1;
51  chest_cfg->filter_type = SRSRAN_CHEST_FILTER_TRIANGLE;
52  chest_cfg->noise_alg = SRSRAN_NOISE_ALG_EMPTY;
53  chest_cfg->rsrp_neighbour = false;
54  chest_cfg->sync_error_enable = false;
55  chest_cfg->estimator_alg = SRSRAN_ESTIMATOR_ALG_INTERPOLATE;
56  chest_cfg->cfo_estimate_enable = false;
57 
58  _ue_dl_cfg.cfg.pdsch.csi_enable = true;
59  _ue_dl_cfg.cfg.pdsch.max_nof_iterations = 8;
60  _ue_dl_cfg.cfg.pdsch.meas_evm_en = false;
61  _ue_dl_cfg.cfg.pdsch.decoder_type = SRSRAN_MIMO_DECODER_MMSE;
62  _ue_dl_cfg.cfg.pdsch.softbuffers.rx[0] = &_softbuffer;
63 
64  _pmch_cfg.pdsch_cfg.csi_enable = true;
65  _pmch_cfg.pdsch_cfg.max_nof_iterations = 8;
66  _pmch_cfg.pdsch_cfg.meas_evm_en = false;
67  _pmch_cfg.pdsch_cfg.decoder_type = SRSRAN_MIMO_DECODER_MMSE;
68 
69  _sf_cfg.sf_type = SRSRAN_SF_MBSFN;
70  return true;
71 }
constexpr unsigned int MAX_PRB
Definition: Phy.h:35
srsran_ue_dl_cfg_t _ue_dl_cfg
srsran_pmch_cfg_t _pmch_cfg

◆ mbsfn_configured()

bool MbsfnFrameProcessor::mbsfn_configured ( )
inline

Returns tru if MBSFN params have already been configured.

Definition at line 108 of file MbsfnFrameProcessor.h.

108 { return _mbsfn_configured; }

◆ mch_data()

auto MbsfnFrameProcessor::mch_data ( ) const

Get the constellation diagram data (I/Q data of the subcarriers after CE)

Definition at line 263 of file MbsfnFrameProcessor.cpp.

263  {
264  const uint8_t* data = reinterpret_cast<uint8_t*>(_ue_dl.pmch.d);
265  return std::move(std::vector<uint8_t>( data, data + _pmch_cfg.pdsch_cfg.grant.nof_re * sizeof(cf_t)));
266 }

◆ 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 83 of file MbsfnFrameProcessor.cpp.

83  {
84  spdlog::trace("Processing MBSFN TTI {}", tti);
85 
86  uint32_t sfn = tti / 10;
87  uint8_t sf = tti % 10;
88 
89  unsigned mch_idx = 0;
90  _sf_cfg.tti = tti;
91  _pmch_cfg.area_id = _area_id;
92  srsran_mbsfn_cfg_t mbsfn_cfg = _phy.mbsfn_config_for_tti(tti, mch_idx);
93  _ue_dl_cfg.chest_cfg.mbsfn_area_id = _area_id;
94  srsran_ue_dl_set_mbsfn_area_id(&_ue_dl, mbsfn_cfg.mbsfn_area_id);
95 
96  if (!_cell.mbms_dedicated) {
97  srsran_ue_dl_set_non_mbsfn_region(&_ue_dl, mbsfn_cfg.non_mbsfn_region_length);
98  }
99 
100  if (sfn%50 == 0) {
101  if (mbsfn_cfg.is_mcch) {
102  _rest._mcch.errors = 0;
103  _rest._mcch.total = 1;
104  } else {
105  _rest._mch[mch_idx].errors = 0;
106  _rest._mch[mch_idx].total = 1;
107  }
108  }
109 
110  if (!mbsfn_cfg.enable) {
111  spdlog::trace("PMCH: tti {}: neither MCCH nor MCH enabled. Skipping subframe");
112  _mutex.unlock();
113  return -1;
114  }
115 
116  if (mbsfn_cfg.is_mcch) {
117  _rest._mcch.total++;
118  } else {
119  _rest._mch[mch_idx].total++;
120  }
121 
122  if (srsran_ue_dl_decode_fft_estimate(&_ue_dl, &_sf_cfg, &_ue_dl_cfg) < 0) {
123  if (mbsfn_cfg.is_mcch) {
124  _rest._mcch.errors++;
125  } else {
126  _rest._mch[mch_idx].errors++;
127  }
128  spdlog::error("Getting PDCCH FFT estimate");
129  _mutex.unlock();
130  return -1;
131  }
132 
133  srsran_configure_pmch(&_pmch_cfg, &_cell, &mbsfn_cfg);
134  srsran_ra_dl_compute_nof_re(&_cell, &_sf_cfg, &_pmch_cfg.pdsch_cfg.grant);
135 
136  _pmch_cfg.area_id = _area_id;
137 
138  srsran_softbuffer_rx_reset_cb(&_softbuffer, 1);
139 
140  srsran_pdsch_res_t pmch_dec = {};
141  _pmch_cfg.pdsch_cfg.softbuffers.rx[0] = &_softbuffer;
142  pmch_dec.payload = _payload_buffer;
143  srsran_softbuffer_rx_reset_tbs(_pmch_cfg.pdsch_cfg.softbuffers.rx[0], _pmch_cfg.pdsch_cfg.grant.tb[0].tbs);
144 
145  if (srsran_ue_dl_decode_pmch(&_ue_dl, &_sf_cfg, &_pmch_cfg, &pmch_dec) != 0) {
146  if (mbsfn_cfg.is_mcch) {
147  _rest._mcch.errors++;
148  } else {
149  _rest._mch[mch_idx].errors++;
150  }
151  spdlog::warn("Error decoding PMCH");
152  _mutex.unlock();
153  return -1;
154  }
155 
156  spdlog::trace("PMCH: tti: {}, l_crb={}, tbs={}, mcs={}, crc={}, snr={} dB, n_iter={}\n",
157  tti,
158  _pmch_cfg.pdsch_cfg.grant.nof_prb,
159  _pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8,
160  _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx,
161  pmch_dec.crc ? "OK" : "KO",
162  _ue_dl.chest_res.snr_db,
163  pmch_dec.avg_iterations_block);
164 
165  if (mbsfn_cfg.is_mcch) {
167  _rest._mcch.mcs = _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx;
168  } else {
169  _rest._mch[mch_idx].SetData(mch_data());
170  _rest._mch[mch_idx].mcs = _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx;
171  _rest._mch[mch_idx].present = true;
172  }
173 
174  if (pmch_dec.crc) {
175  mch_mac_msg.init_rx(
176  static_cast<uint32_t>(_pmch_cfg.pdsch_cfg.grant.tb[0].tbs) / 8);
177  mch_mac_msg.parse_packet(_payload_buffer);
178 
179  while (mch_mac_msg.next()) {
180  if (srsran::mch_lcid::MCH_SCHED_INFO == mch_mac_msg.get()->mch_ce_type()) {
181  uint16_t stop = 0;
182  uint8_t lcid = 0;
183  while (mch_mac_msg.get()->get_next_mch_sched_info(&lcid, &stop)) {
184  const std::lock_guard<std::mutex> lock(_sched_stop_mutex);
185  spdlog::debug("Scheduling stop for LCID {} in sf {}", lcid, stop);
186  _sched_stops[ lcid ] = stop;
187  }
188  } else if (mch_mac_msg.get()->is_sdu()) {
189  uint32_t lcid = mch_mac_msg.get()->get_sdu_lcid();
190  spdlog::trace("Processing MAC MCH PDU entered, lcid {}", lcid);
191 
192  if (lcid >= SRSRAN_N_MCH_LCIDS) {
193  spdlog::warn("Radio bearer id must be in [0:%d] - %d", SRSRAN_N_MCH_LCIDS, lcid);
194  if (mbsfn_cfg.is_mcch) {
195  _rest._mcch.errors++;
196  } else {
197  _rest._mch[mch_idx].errors++;
198  }
199  _mutex.unlock();
200  return -1;
201  }
202 
203  {
204  const std::lock_guard<std::mutex> lock(_rlc_mutex);
205  _phy._mcs = mbsfn_cfg.mbsfn_mcs;
206  _rlc.write_pdu_mch(mch_idx, lcid, mch_mac_msg.get()->get_sdu_ptr(), mch_mac_msg.get()->get_payload_size());
207  }
208  }
209  }
210  } else {
211  if (mbsfn_cfg.is_mcch) {
212  _rest._mcch.errors++;
213  } else {
214  _rest._mch[mch_idx].errors++;
215  }
216 
217  spdlog::warn("PMCH in TTI {} failed with CRC error", tti);
218  _mutex.unlock();
219  return -1;
220  }
221 
222  if (!mbsfn_cfg.is_mcch) {
223  for (uint32_t i = 0; i < _phy.mcch().nof_pmch_info; i++) {
224  unsigned fn_in_scheduling_period = sfn % srsran::enum_to_number(_phy.mcch().pmch_info_list[i].mch_sched_period);
225  unsigned sf_idx;
226  if (_cell.mbms_dedicated) {
227  sf_idx = fn_in_scheduling_period * 10 + sf - (fn_in_scheduling_period / 4) - 1;
228  } else {
229  sf_idx = fn_in_scheduling_period * 6 + (sf < 6 ? sf - 1 : sf - 3);
230  }
231  spdlog::debug("tti{}, sfn {}, sf {}, fn_in_scheduling_period {}, sf_idf {}", tti, sfn, sf, fn_in_scheduling_period, sf_idx);
232 
233  const std::lock_guard<std::mutex> lock(_sched_stop_mutex);
234  for (auto itr = _sched_stops.cbegin() ; itr != _sched_stops.cend() ;) {
235  if ( sf_idx >= itr->second ) {
236  const std::lock_guard<std::mutex> lock(_rlc_mutex);
237  spdlog::debug("Stopping LCID {} in tti {} (idx in rf {})", itr->first, tti, sf_idx);
238  _rlc.stop_mch(i, itr->first);
239  itr = _sched_stops.erase(itr);
240  } else {
241  itr = std::next(itr);
242  }
243  }
244  }
245  } else {
246  _rlc.stop_mch(0, 0);
247  _rest._mcch.present = true;
248  }
249  _mutex.unlock();
250  return mbsfn_cfg.is_mcch ? 0 : 1;
251 }
static std::map< uint8_t, uint16_t > _sched_stops
static std::mutex _rlc_mutex
uint8_t _payload_buffer[_payload_buffer_sz]
static std::mutex _sched_stop_mutex
const std::vector< uint8_t > mch_data() const
Get the constellation diagram data (I/Q data of the subcarriers after CE)
srsran_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:324
int _mcs
Definition: Phy.h:211
srsran::mcch_msg_t & mcch()
Definition: Phy.h:209
void SetData(std::vector< uint8_t > data)
Definition: RestHandler.h:72
ChannelInfo _mcch
RX info for MCCH.
Definition: RestHandler.h:103
std::map< uint32_t, ChannelInfo > _mch
RX info for MCHs.
Definition: RestHandler.h:108

◆ rx_buffer_size()

uint32_t MbsfnFrameProcessor::rx_buffer_size ( )
inline

Size of the signal buffer.

Definition at line 98 of file MbsfnFrameProcessor.h.

◆ set_cell()

void MbsfnFrameProcessor::set_cell ( srsran_cell_t  cell)

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

Parameters
cellThe cell we're camping on

Definition at line 78 of file MbsfnFrameProcessor.cpp.

78  {
79  _cell = cell;
80  srsran_ue_dl_set_cell(&_ue_dl, cell);
81 }

◆ unlock()

void MbsfnFrameProcessor::unlock ( )
inline

Unlock the processor.

See also
get_rx_buffer_and_lock()

Definition at line 115 of file MbsfnFrameProcessor.h.

115 { _mutex.unlock(); }

Member Data Documentation

◆ _area_id

uint8_t MbsfnFrameProcessor::_area_id = 1
private

Definition at line 146 of file MbsfnFrameProcessor.h.

◆ _cell

srsran_cell_t MbsfnFrameProcessor::_cell
private

Definition at line 132 of file MbsfnFrameProcessor.h.

◆ _cfg

const libconfig::Config& MbsfnFrameProcessor::_cfg
private

Definition at line 128 of file MbsfnFrameProcessor.h.

◆ _current_mcs

int MbsfnFrameProcessor::_current_mcs
staticprivate

Definition at line 160 of file MbsfnFrameProcessor.h.

◆ _mbsfn_configured

bool MbsfnFrameProcessor::_mbsfn_configured = false
private

Definition at line 147 of file MbsfnFrameProcessor.h.

◆ _mutex

std::mutex MbsfnFrameProcessor::_mutex
private

Definition at line 150 of file MbsfnFrameProcessor.h.

◆ _payload_buffer

uint8_t MbsfnFrameProcessor::_payload_buffer[_payload_buffer_sz]
private

Definition at line 138 of file MbsfnFrameProcessor.h.

◆ _payload_buffer_sz

const uint32_t MbsfnFrameProcessor::_payload_buffer_sz = SRSRAN_MAX_BUFFER_SIZE_BYTES
staticprivate

Definition at line 137 of file MbsfnFrameProcessor.h.

◆ _phy

Phy& MbsfnFrameProcessor::_phy
private

Definition at line 130 of file MbsfnFrameProcessor.h.

◆ _pmch_cfg

srsran_pmch_cfg_t MbsfnFrameProcessor::_pmch_cfg = {}
private

Definition at line 144 of file MbsfnFrameProcessor.h.

◆ _rest

RestHandler& MbsfnFrameProcessor::_rest
private

Definition at line 152 of file MbsfnFrameProcessor.h.

◆ _rlc

srsran::rlc& MbsfnFrameProcessor::_rlc
private

Definition at line 129 of file MbsfnFrameProcessor.h.

◆ _rlc_mutex

std::mutex MbsfnFrameProcessor::_rlc_mutex
staticprivate

Definition at line 159 of file MbsfnFrameProcessor.h.

◆ _rx_channels

unsigned MbsfnFrameProcessor::_rx_channels
private

Definition at line 154 of file MbsfnFrameProcessor.h.

◆ _sched_stop_mutex

std::mutex MbsfnFrameProcessor::_sched_stop_mutex
staticprivate

Definition at line 156 of file MbsfnFrameProcessor.h.

◆ _sched_stops

std::map< uint8_t, uint16_t > MbsfnFrameProcessor::_sched_stops
staticprivate

Definition at line 157 of file MbsfnFrameProcessor.h.

◆ _sf_cfg

srsran_dl_sf_cfg_t MbsfnFrameProcessor::_sf_cfg = {}
private

Definition at line 143 of file MbsfnFrameProcessor.h.

◆ _signal_buffer_max_samples

uint32_t MbsfnFrameProcessor::_signal_buffer_max_samples = 0
private

Definition at line 135 of file MbsfnFrameProcessor.h.

◆ _signal_buffer_rx

cf_t* MbsfnFrameProcessor::_signal_buffer_rx[SRSRAN_MAX_PORTS] = {}
private

Definition at line 134 of file MbsfnFrameProcessor.h.

◆ _softbuffer

srsran_softbuffer_rx_t MbsfnFrameProcessor::_softbuffer
private

Definition at line 139 of file MbsfnFrameProcessor.h.

◆ _ue_dl

srsran_ue_dl_t MbsfnFrameProcessor::_ue_dl = {}
private

Definition at line 141 of file MbsfnFrameProcessor.h.

◆ _ue_dl_cfg

srsran_ue_dl_cfg_t MbsfnFrameProcessor::_ue_dl_cfg = {}
private

Definition at line 142 of file MbsfnFrameProcessor.h.

◆ mch_mac_msg

srsran::mch_pdu MbsfnFrameProcessor::mch_mac_msg
private

Definition at line 149 of file MbsfnFrameProcessor.h.


The documentation for this class was generated from the following files: