20 #include "MbsfnFrameProcessor.h"
21 #include "spdlog/spdlog.h"
22 #include "srslte/interfaces/ue_interfaces.h"
24 std::map<uint8_t, uint16_t> MbsfnFrameProcessor::_sched_stops;
26 std::mutex MbsfnFrameProcessor::_sched_stop_mutex;
27 std::mutex MbsfnFrameProcessor::_rlc_mutex;
30 _signal_buffer_max_samples = 3 * SRSLTE_SF_LEN_PRB(MAX_PRB);
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");
38 if (srslte_ue_dl_init(&_ue_dl, _signal_buffer_rx, MAX_PRB, 1) != 0) {
39 spdlog::error(
"Could not init ue_dl\n");
43 srslte_softbuffer_rx_init(&_softbuffer, 100);
45 _ue_dl_cfg.snr_to_cqi_offset = 0;
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;
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;
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;
68 _sf_cfg.sf_type = SRSLTE_SF_MBSFN;
73 srslte_softbuffer_rx_free(&_softbuffer);
74 srslte_ue_dl_free(&_ue_dl);
79 srslte_ue_dl_set_cell(&_ue_dl, cell);
83 spdlog::trace(
"Processing MBSFN TTI {}", tti);
85 uint32_t sfn = tti / 10;
86 uint8_t sf = tti % 10;
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;
95 if (mbsfn_cfg.is_mcch) {
96 _rest._mcch.errors = 0;
97 _rest._mcch.total = 1;
99 _rest._mch[area].errors = 0;
100 _rest._mch[area].total = 1;
104 if (!mbsfn_cfg.enable) {
109 if (mbsfn_cfg.is_mcch) {
112 _rest._mch[area].total++;
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++;
119 _rest._mch[area].errors++;
121 spdlog::error(
"Getting PDCCH FFT estimate");
126 srslte_configure_pmch(&_pmch_cfg, &_cell, &mbsfn_cfg);
127 srslte_ra_dl_compute_nof_re(&_cell, &_sf_cfg, &_pmch_cfg.pdsch_cfg.grant);
129 _pmch_cfg.area_id = _area_id;
131 srslte_softbuffer_rx_reset_cb(&_softbuffer, 1);
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);
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++;
142 _rest._mch[area].errors++;
144 spdlog::warn(
"Error decoding PMCH");
149 spdlog::trace(
"PMCH: tti: {}, l_crb={}, tbs={}, mcs={}, crc={}, snr={} dB, n_iter={}\n",
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);
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;
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;
171 static_cast<uint32_t
>(_pmch_cfg.pdsch_cfg.grant.tb[0].tbs) / 8);
172 mch_mac_msg.parse_packet(_payload_buffer);
174 while (mch_mac_msg.next()) {
175 if (srslte::mch_lcid::MCH_SCHED_INFO == mch_mac_msg.get()->mch_ce_type()) {
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;
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);
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++;
192 _rest._mch[area].errors++;
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());
206 if (mbsfn_cfg.is_mcch) {
207 _rest._mcch.errors++;
209 _rest._mch[area].errors++;
212 spdlog::warn(
"PMCH in TTI {} failed with CRC error", tti);
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;
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);
230 itr = std::next(itr);
235 _rest._mcch.present =
true;
238 return mbsfn_cfg.is_mcch ? 0 : 1;
242 _sf_cfg.subcarrier_spacing = subcarrier_spacing;
243 srslte_ue_dl_set_mbsfn_subcarrier_spacing(&_ue_dl, subcarrier_spacing);
244 srslte_ue_dl_set_mbsfn_area_id(&_ue_dl, area_id);
246 _mbsfn_configured =
true;
250 const uint8_t* data =
reinterpret_cast<uint8_t*
>(_ue_dl.pmch.d);
251 return std::move(std::vector<uint8_t>( data, data + _pmch_cfg.pdsch_cfg.grant.nof_re *
sizeof(cf_t)));