21 #include "spdlog/spdlog.h"
29 _signal_buffer_max_samples = 3 * SRSRAN_SF_LEN_PRB(
MAX_PRB);
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");
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");
44 srsran_softbuffer_rx_init(&_softbuffer, 100);
46 _ue_dl_cfg.snr_to_cqi_offset = 0;
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;
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;
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;
69 _sf_cfg.sf_type = SRSRAN_SF_MBSFN;
75 srsran_ue_dl_free(&
_ue_dl);
80 srsran_ue_dl_set_cell(&
_ue_dl, cell);
84 spdlog::trace(
"Processing MBSFN TTI {}", tti);
86 uint32_t sfn = tti / 10;
87 uint8_t sf = tti % 10;
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);
96 if (!_cell.mbms_dedicated) {
97 srsran_ue_dl_set_non_mbsfn_region(&_ue_dl, mbsfn_cfg.non_mbsfn_region_length);
101 if (mbsfn_cfg.is_mcch) {
102 _rest._mcch.errors = 0;
103 _rest._mcch.total = 1;
105 _rest._mch[mch_idx].errors = 0;
106 _rest._mch[mch_idx].total = 1;
110 if (!mbsfn_cfg.enable) {
111 spdlog::trace(
"PMCH: tti {}: neither MCCH nor MCH enabled. Skipping subframe");
116 if (mbsfn_cfg.is_mcch) {
119 _rest._mch[mch_idx].total++;
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++;
126 _rest._mch[mch_idx].errors++;
128 spdlog::error(
"Getting PDCCH FFT estimate");
133 srsran_configure_pmch(&_pmch_cfg, &_cell, &mbsfn_cfg);
134 srsran_ra_dl_compute_nof_re(&_cell, &_sf_cfg, &_pmch_cfg.pdsch_cfg.grant);
136 _pmch_cfg.area_id = _area_id;
138 srsran_softbuffer_rx_reset_cb(&_softbuffer, 1);
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);
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++;
149 _rest._mch[mch_idx].errors++;
151 spdlog::warn(
"Error decoding PMCH");
156 spdlog::trace(
"PMCH: tti: {}, l_crb={}, tbs={}, mcs={}, crc={}, snr={} dB, n_iter={}\n",
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);
165 if (mbsfn_cfg.is_mcch) {
166 _rest._mcch.SetData(mch_data());
167 _rest._mcch.mcs = _pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx;
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;
176 static_cast<uint32_t
>(_pmch_cfg.pdsch_cfg.grant.tb[0].tbs) / 8);
177 mch_mac_msg.parse_packet(_payload_buffer);
179 while (mch_mac_msg.next()) {
180 if (srsran::mch_lcid::MCH_SCHED_INFO == mch_mac_msg.get()->mch_ce_type()) {
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;
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);
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++;
197 _rest._mch[mch_idx].errors++;
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());
211 if (mbsfn_cfg.is_mcch) {
212 _rest._mcch.errors++;
214 _rest._mch[mch_idx].errors++;
217 spdlog::warn(
"PMCH in TTI {} failed with CRC error", tti);
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);
226 if (_cell.mbms_dedicated) {
227 sf_idx = fn_in_scheduling_period * 10 + sf - (fn_in_scheduling_period / 4) - 1;
229 sf_idx = fn_in_scheduling_period * 6 + (sf < 6 ? sf - 1 : sf - 3);
231 spdlog::debug(
"tti{}, sfn {}, sf {}, fn_in_scheduling_period {}, sf_idf {}", tti, sfn, sf, fn_in_scheduling_period, sf_idx);
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);
241 itr = std::next(itr);
247 _rest._mcch.present =
true;
250 return mbsfn_cfg.is_mcch ? 0 : 1;
254 _sf_cfg.subcarrier_spacing = subcarrier_spacing;
255 srsran_ue_dl_set_mbsfn_subcarrier_spacing(&
_ue_dl, subcarrier_spacing);
258 srsran_ue_dl_set_mbsfn_area_id(&
_ue_dl, area_id);
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)));
constexpr unsigned int MAX_PRB
srsran_softbuffer_rx_t _softbuffer
static std::map< uint8_t, uint16_t > _sched_stops
bool init()
Initialize signal- and softbuffers, init all underlying components.
void set_cell(srsran_cell_t cell)
Set the parameters for the cell (Nof PRB, etc).
srsran_dl_sf_cfg_t _sf_cfg
static std::mutex _rlc_mutex
virtual ~MbsfnFrameProcessor()
Default destructor.
int process(uint32_t tti)
Process the sample data in the signal buffer.
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_pmch_cfg_t _pmch_cfg
void configure_mbsfn(uint8_t area_id, srsran_scs_t subcarrier_spacing)
Set MBSFN parameters: area ID and subcarrier spacing.