5G-MAG Reference Tools - MBMS Modem
CasFrameProcessor.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Modem Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
15 //
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 #include "CasFrameProcessor.h"
21 #include "spdlog/spdlog.h"
22 
23 
24 auto CasFrameProcessor::init() -> bool {
25  _signal_buffer_max_samples = 3 * SRSRAN_SF_LEN_PRB(MAX_PRB);
26 
27  for (auto ch = 0; ch < _rx_channels; ch++) {
28  _signal_buffer_rx[ch] = srsran_vec_cf_malloc(_signal_buffer_max_samples);
29  if (!_signal_buffer_rx[ch]) {
30  spdlog::error("Could not allocate regular DL signal buffer\n");
31  return false;
32  }
33  }
34 
35  if (srsran_ue_dl_init(&_ue_dl, _signal_buffer_rx, MAX_PRB, _rx_channels)) {
36  spdlog::error("Could not init ue_dl\n");
37  return false;;
38  }
39 
40  srsran_softbuffer_rx_init(&_softbuffer, 100);
41 
42  _ue_dl_cfg.snr_to_cqi_offset = 0;
43 
44  for (auto & i : _data) {
45  i = srsran_vec_u8_malloc(2000 * 8);
46  if (!i) {
47  spdlog::error("Allocating data");
48  return false;
49  }
50  }
51 
52  srsran_chest_dl_cfg_t* chest_cfg = &_ue_dl_cfg.chest_cfg;
53  bzero(chest_cfg, sizeof(srsran_chest_dl_cfg_t));
54  chest_cfg->filter_coef[0] = 4;
55  chest_cfg->filter_coef[1] = 0.2f;
56  chest_cfg->filter_type = SRSRAN_CHEST_FILTER_GAUSS;
57  chest_cfg->noise_alg = SRSRAN_NOISE_ALG_EMPTY;
58  chest_cfg->rsrp_neighbour = false;
59  chest_cfg->sync_error_enable = true;
60  chest_cfg->estimator_alg = SRSRAN_ESTIMATOR_ALG_AVERAGE;
61  chest_cfg->cfo_estimate_enable = true;
62  chest_cfg->cfo_estimate_sf_mask = 1023;
63 
64  _ue_dl_cfg.cfg.pdsch.csi_enable = true;
65  _ue_dl_cfg.cfg.pdsch.max_nof_iterations = 8;
66  _ue_dl_cfg.cfg.pdsch.meas_evm_en = false;
67  _ue_dl_cfg.cfg.pdsch.decoder_type = SRSRAN_MIMO_DECODER_MMSE;
68  _ue_dl_cfg.cfg.pdsch.softbuffers.rx[0] = &_softbuffer;
69 
70  _sf_cfg.sf_type = SRSRAN_SF_NORM;
71  return true;
72 }
73 
75  for (auto & i : _data) {
76  if (i) {
77  free(i);
78  }
79  }
80  srsran_softbuffer_rx_free(&_softbuffer);
81  srsran_ue_dl_free(&_ue_dl);
82 }
83 
84 void CasFrameProcessor::set_cell(srsran_cell_t cell) {
85  _cell = cell;
86  spdlog::debug("CAS processor setting cell ({} PRB / {} MBSFN PRB).", cell.nof_prb, cell.mbsfn_prb);
87  srsran_ue_dl_set_cell(&_ue_dl, cell);
88  _started = true;
89 }
90 
91 auto CasFrameProcessor::process(uint32_t tti) -> bool {
92  _sf_cfg.tti = tti;
93 
94  _rest._pdsch.total++;
95 
96  // Run the FFT and do channel estimation
97  if (srsran_ue_dl_decode_fft_estimate(&_ue_dl, &_sf_cfg, &_ue_dl_cfg) < 0) {
98  _rest._pdsch.errors++;
99  spdlog::error("Getting PDCCH FFT estimate\n");
100  _mutex.unlock();
101  return false;
102  }
103 
104  // Feedback the CFO from CE to the Phy
105  _phy.set_cfo_from_channel_estimation(_ue_dl.chest_res.cfo);
106 
107  // Try to decode DCIs from PDCCH
108  srsran_dci_dl_t dci[SRSRAN_MAX_CARRIERS] = {}; // NOLINT
109  int nof_grants = srsran_ue_dl_find_dl_dci(&_ue_dl, &_sf_cfg, &_ue_dl_cfg, _cell.mbms_dedicated ? SRSRAN_SIRNTI_MBMS_DEDICATED : SRSRAN_SIRNTI, dci);
110  for (int k = 0; k < nof_grants; k++) {
111  char str[512]; // NOLINT
112  srsran_dci_dl_info(&dci[k], str, 512);
113  _rest._pdsch.mcs = dci[k].tb[0].mcs_idx;
114  spdlog::debug("Decoded PDCCH: {}, snr={} dB\n", str, _ue_dl.chest_res.snr_db);
115 
116  if (srsran_ue_dl_dci_to_pdsch_grant(&_ue_dl, &_sf_cfg, &_ue_dl_cfg, &dci[k], &_ue_dl_cfg.cfg.pdsch.grant)) {
117  spdlog::error("Converting DCI message to DL dci\n");
118  _mutex.unlock();
119  return false;
120  }
121 
122  // We can construct a DL grant
123  _ue_dl_cfg.cfg.pdsch.rnti = dci[k].rnti;
124  srsran_pdsch_cfg_t* pdsch_cfg = &_ue_dl_cfg.cfg.pdsch;
125 
126  srsran_pdsch_res_t pdsch_res[SRSRAN_MAX_CODEWORDS] = {}; // NOLINT
127  for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
128  if (pdsch_cfg->grant.tb[i].enabled) {
129  if (pdsch_cfg->grant.tb[i].rv < 0) {
130  uint32_t sfn = tti / 10;
131  uint32_t k = (sfn / 2) % 4;
132  pdsch_cfg->grant.tb[i].rv = ((int32_t)ceilf(static_cast<float>(1.5) * k)) % 4;
133  }
134  pdsch_res[i].payload = _data[i];
135  pdsch_res[i].crc = false;
136  srsran_softbuffer_rx_reset_tbs(pdsch_cfg->softbuffers.rx[i], (uint32_t)pdsch_cfg->grant.tb[i].tbs);
137  }
138  }
139 
140  _rest._pdsch.SetData(pdsch_data());
141  _rest._ce_values = std::move(ce_values());
142 
143  // Decode PDSCH..
144  auto ret = srsran_ue_dl_decode_pdsch(&_ue_dl, &_sf_cfg, &_ue_dl_cfg.cfg.pdsch, pdsch_res);
145  if (ret) {
146  spdlog::error("Error decoding PDSCH\n");
147  _rest._pdsch.errors++;
148  } else {
149  spdlog::debug("Decoded PDSCH");
150  _rest._pdsch.evm_rms = pdsch_res[0].evm; // evm of the first codeword
151  for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
152  // .. and pass received PDUs to RLC for further processing
153  if (pdsch_cfg->grant.tb[i].enabled && pdsch_res[i].crc) {
154  _rlc.write_pdu_bcch_dlsch(_data[i], (uint32_t)pdsch_cfg->grant.tb[i].tbs);
155  }
156  }
157  }
158  }
159  _mutex.unlock();
160  return true;
161 }
162 
163 auto CasFrameProcessor::ce_values() -> std::vector<uint8_t> {
164  auto sz = (uint32_t)srsran_symbol_sz(_cell.nof_prb);
165  std::vector<float> ce_abs;
166  ce_abs.resize(sz, 0);
167  uint32_t g = (sz - 12 * _cell.nof_prb) / 2;
168  srsran_vec_abs_dB_cf(_ue_dl.chest_res.ce[0][0], -80, &ce_abs[g], SRSRAN_NRE * _cell.nof_prb);
169  const uint8_t* data = reinterpret_cast<uint8_t*>(ce_abs.data());
170  return std::vector<uint8_t>( data, data + sz * sizeof(float));
171 }
172 
173 auto CasFrameProcessor::pdsch_data() -> std::vector<uint8_t> {
174  const uint8_t* data = reinterpret_cast<uint8_t*>(_ue_dl.pdsch.d[0]);
175  return std::vector<uint8_t>( data, data + _ue_dl_cfg.cfg.pdsch.grant.nof_re * sizeof(cf_t));
176 }
constexpr unsigned int MAX_PRB
Definition: Phy.h:35
srsran_softbuffer_rx_t _softbuffer
std::vector< uint8_t > ce_values()
Get the CE values (time domain) for displaying the spectrum of the received signal.
uint8_t * _data[SRSRAN_MAX_CODEWORDS]
virtual ~CasFrameProcessor()
Default destructor.
srsran_ue_dl_t _ue_dl
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).
std::vector< uint8_t > pdsch_data()
Get the constellation diagram data (I/Q data of the subcarriers after CE)
bool process(uint32_t tti)
Process the sample data in the signal buffer.