24 #include "spdlog/spdlog.h"
25 #include "srslte/asn1/rrc_asn1_utils.h"
27 static auto receive_callback(
void* obj, cf_t* data[SRSLTE_MAX_CHANNELS],
28 uint32_t nsamples, srslte_timestamp_t* rx_time)
30 return (
static_cast<Phy*
>(obj))->_sample_cb(data[0], nsamples, rx_time);
33 const uint32_t kMaxBufferSamples = 2 * 15360;
34 const uint32_t kMaxSfn = 1024;
35 const uint32_t kSfnOffset = 4;
36 const uint32_t kSubframesPerFrame = 10;
38 const uint32_t kMaxCellsToDiscover = 3;
41 int8_t override_nof_prb)
43 _sample_cb(std::move(std::move(cb))),
44 _cs_nof_prb(cs_nof_prb),
45 _override_nof_prb(override_nof_prb) {
46 _buffer_max_samples = kMaxBufferSamples;
47 _mib_buffer[0] =
static_cast<cf_t*
>(malloc(_buffer_max_samples *
sizeof(cf_t)));
51 srslte_ue_sync_free(&_ue_sync);
57 int ret = srslte_ue_sync_zerocopy(&_ue_sync, _mib_buffer, _buffer_max_samples);
59 spdlog::error(
"SYNC: Error calling ue_sync_get_buffer.\n");
64 std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN> bch_payload = {};
65 if (srslte_ue_sync_get_sfidx(&_ue_sync) == 0) {
68 srslte_ue_mib_decode(&_mib, bch_payload.data(),
nullptr, &sfn_offset);
71 srslte_pbch_mib_mbms_unpack(bch_payload.data(), &_cell, &sfn,
nullptr,
73 sfn = (sfn + sfn_offset * kSfnOffset) % kMaxSfn;
74 _tti = sfn * kSubframesPerFrame;
83 std::array<srslte_ue_cellsearch_result_t, kMaxCellsToDiscover> found_cells = {0};
85 uint32_t max_peak_cell = 0;
86 int ret = srslte_ue_cellsearch_scan(&_cell_search, found_cells.data(), &max_peak_cell);
88 spdlog::error(
"Phy: Error decoding MIB: Error searching PSS\n");
92 spdlog::error(
"Phy: Could not find any cell in this frequency\n");
96 srslte_cell_t new_cell = {};
97 new_cell.id = found_cells.at(max_peak_cell).cell_id;
98 new_cell.cp = found_cells.at(max_peak_cell).cp;
99 new_cell.frame_type = found_cells.at(max_peak_cell).frame_type;
100 new_cell.mbms_dedicated =
true;
101 float cfo = found_cells.at(max_peak_cell).cfo;
103 spdlog::info(
"Phy: PSS/SSS detected: Mode {}, PCI {}, CFO {} KHz, CP {}",
104 new_cell.frame_type != 0U ?
"TDD" :
"FDD", new_cell.id,
105 cfo / 1000, srslte_cp_string(new_cell.cp));
107 if (srslte_ue_mib_sync_set_cell_prb(&_mib_sync, new_cell, _cs_nof_prb) != 0) {
108 spdlog::error(
"Phy: Error setting UE MIB sync cell");
112 srslte_ue_sync_reset(&_mib_sync.ue_sync);
114 std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN> bch_payload = {};
117 ret = srslte_ue_mib_sync_decode_prb(&_mib_sync, 40, bch_payload.data(), &new_cell.nof_ports, &sfn_offset, _cs_nof_prb);
120 srslte_pbch_mib_mbms_unpack(bch_payload.data(), &new_cell, &sfn,
nullptr,
124 "Phy: MIB Decoded. Mode {}, PCI {}, PRB {}, Ports {}, CFO {} KHz, SFN "
126 new_cell.frame_type != 0u ?
"TDD" :
"FDD", new_cell.id,
127 new_cell.nof_prb, new_cell.nof_ports, cfo / 1000, sfn);
129 if (!srslte_cell_isvalid(&new_cell)) {
130 spdlog::error(
"SYNC: Detected invalid cell.\n");
135 _cell.mbsfn_prb = _cell.nof_prb;
137 if (srslte_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
138 spdlog::error(
"Phy: failed to set cell.\n");
141 if (srslte_ue_mib_set_cell(&_mib, cell()) != 0) {
142 spdlog::error(
"Phy: Error setting UE MIB cell");
149 spdlog::error(
"Phy: failed to receive MIB\n");
153 auto Phy::set_cell() ->
void {
154 if (srslte_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
155 spdlog::error(
"Phy: failed to set cell.\n");
157 if (srslte_ue_mib_set_cell(&_mib, cell()) != 0) {
158 spdlog::error(
"Phy: Error setting UE MIB cell");
163 if (srslte_ue_cellsearch_init_multi_prb_cp(&_cell_search, 8, receive_callback, 1,
164 this, _cs_nof_prb,
true) != 0) {
165 spdlog::error(
"Phy: error while initiating UE cell search\n");
168 srslte_ue_cellsearch_set_nof_valid_frames(&_cell_search, 4);
170 if (srslte_ue_sync_init_multi(&_ue_sync, MAX_PRB,
false, receive_callback, 1,
172 spdlog::error(
"Cannot init ue_sync");
176 if (srslte_ue_mib_sync_init_multi_prb(&_mib_sync, receive_callback, 1,
this,
178 spdlog::error(
"Cannot init ue_mib_sync");
182 if (srslte_ue_mib_init(&_mib, _mib_buffer[0], 50) != 0) {
183 spdlog::error(
"Cannot init ue_mib");
191 return 1 == srslte_ue_sync_zerocopy(&_ue_sync, buffer, size);
195 if (sib13.nof_mbsfn_area_info > 1) {
196 spdlog::warn(
"SIB13 has {} MBSFN area info elements - only 1 supported", sib13.nof_mbsfn_area_info);
199 if (sib13.mbsfn_area_info_list[0].pmch_bandwidth != 0) {
200 _cell.mbsfn_prb = sib13.mbsfn_area_info_list[0].pmch_bandwidth;
203 if (sib13.nof_mbsfn_area_info > 0) {
206 bzero(&_mcch_table[0],
sizeof(uint8_t) * 10);
207 if (sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info_is_r16) {
208 generate_mcch_table_r16(
210 static_cast<uint32_t
>(
211 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
215 static_cast<uint32_t
>(
216 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
219 std::stringstream ss;
221 for (
unsigned char j : _mcch_table) {
222 ss << static_cast<int>(j) <<
"|";
224 spdlog::debug(
"MCCH table: {}", ss.str());
226 _mcch_configured =
true;
232 _mch_configured =
true;
235 for (uint32_t i = 0; i < _mcch.nof_pmch_info; i++) {
237 mch_info.mcs = _mcch.pmch_info_list[i].data_mcs;
239 for (uint32_t j = 0; j < _mcch.pmch_info_list[i].nof_mbms_session_info; j++) {
241 mtch_info.lcid = _mcch.pmch_info_list[i].mbms_session_info_list[j].lc_ch_id;
243 for (
int k = 1; k < 3; k++) {
244 tmgi += std::to_string(_mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[k]);
246 tmgi += _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.to_string();
247 mtch_info.tmgi = tmgi;
248 mtch_info.dest = _dests[mch_info.mcs][mtch_info.lcid];
249 mch_info.mtchs.push_back(mtch_info);
252 _mch_info.push_back(mch_info);
257 -> srslte_mbsfn_cfg_t {
258 srslte_mbsfn_cfg_t cfg;
262 if (!_mcch_configured) {
268 uint32_t sfn = tti / 10;
269 uint8_t sf = tti % 10;
271 srslte::mbsfn_area_info_t& area_info = _sib13.mbsfn_area_info_list[0];
273 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
274 cfg.non_mbsfn_region_length = enum_to_number(area_info.non_mbsfn_region_len);
276 if (sfn % enum_to_number(area_info.mcch_cfg.mcch_repeat_period) == area_info.mcch_cfg.mcch_offset &&
277 _mcch_table[sf] == 1) {
280 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
285 if (_mch_configured) {
286 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
288 for (uint32_t i = 0; i < _mcch.nof_pmch_info; i++) {
289 unsigned fn_in_scheduling_period = sfn % enum_to_number(_mcch.pmch_info_list[i].mch_sched_period);
290 unsigned sf_idx = fn_in_scheduling_period * 10 + sf - (fn_in_scheduling_period / 4) - 1;
292 spdlog::debug(
"tti {}, fn_in_ {}, sf_idx {}", tti, fn_in_scheduling_period, sf_idx);
294 if (sf_idx <= _mcch.pmch_info_list[i].sf_alloc_end) {
296 if ((i == 0 && fn_in_scheduling_period == 0 && sf == 1) ||
297 (i > 0 && _mcch.pmch_info_list[i-1].sf_alloc_end + 1 == sf_idx)) {
298 spdlog::debug(
"assigning sig_mcs {}", area_info.mcch_cfg.sig_mcs);
299 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
301 spdlog::debug(
"assigning pmch_mcs {}", area_info.mcch_cfg.sig_mcs);
302 cfg.mbsfn_mcs = _mcch.pmch_info_list[i].data_mcs;