25 #include "srsran/interfaces/rrc_interface_types.h"
26 #include "srsran/asn1/rrc_utils.h"
27 #include "spdlog/spdlog.h"
30 uint32_t nsamples, srsran_timestamp_t* rx_time)
32 return (
static_cast<Phy*
>(obj))->_sample_cb(data, nsamples, rx_time);
43 int8_t override_nof_prb, uint8_t rx_channels)
45 _sample_cb(std::move(std::move(cb))),
46 _cs_nof_prb(cs_nof_prb),
47 _override_nof_prb(override_nof_prb),
48 _rx_channels(rx_channels) {
61 int ret = srsran_ue_sync_zerocopy(&_ue_sync, _mib_buffer, _buffer_max_samples);
63 spdlog::error(
"SYNC: Error calling ue_sync_get_buffer.\n");
68 std::array<uint8_t, SRSRAN_BCH_PAYLOAD_LEN> bch_payload = {};
69 if (srsran_ue_sync_get_sfidx(&_ue_sync) == 0) {
72 srsran_ue_mib_decode(&_mib, bch_payload.data(),
nullptr, &sfn_offset);
75 if (_cell.mbms_dedicated) {
76 srsran_pbch_mib_mbms_unpack(bch_payload.data(), &_cell, &sfn,
nullptr,
80 srsran_pbch_mib_unpack(bch_payload.data(), &_cell, &sfn);
81 sfn = (sfn + sfn_offset) %
kMaxSfn;
92 std::array<srsran_ue_cellsearch_result_t, kMaxCellsToDiscover> found_cells = {0};
94 uint32_t max_peak_cell = 0;
95 int ret = srsran_ue_cellsearch_scan(&_cell_search, found_cells.data(), &max_peak_cell);
97 spdlog::error(
"Phy: Error decoding MIB: Error searching PSS\n");
101 spdlog::error(
"Phy: Could not find any cell in this frequency\n");
105 srsran_cell_t new_cell = {};
106 new_cell.id = found_cells.at(max_peak_cell).cell_id;
107 new_cell.cp = found_cells.at(max_peak_cell).cp;
108 new_cell.frame_type = found_cells.at(max_peak_cell).frame_type;
109 float cfo = found_cells.at(max_peak_cell).cfo;
111 spdlog::info(
"Phy: PSS/SSS detected: Mode {}, PCI {}, CFO {} KHz, CP {}",
112 new_cell.frame_type != 0U ?
"TDD" :
"FDD", new_cell.id,
113 cfo / 1000, srsran_cp_string(new_cell.cp));
117 std::array<uint8_t, SRSRAN_BCH_PAYLOAD_LEN> bch_payload = {};
122 new_cell.mbms_dedicated =
true;
123 if (srsran_ue_mib_sync_set_cell_prb(&_mib_sync, new_cell, _cs_nof_prb) != 0) {
124 spdlog::error(
"Phy: Error setting UE MIB sync cell");
127 srsran_ue_sync_reset(&_mib_sync.ue_sync);
128 ret = srsran_ue_mib_sync_decode_prb(&_mib_sync, 40, bch_payload.data(), &new_cell.nof_ports, &sfn_offset, _cs_nof_prb);
132 new_cell.mbms_dedicated =
false;
133 if (srsran_ue_mib_sync_set_cell_prb(&_mib_sync, new_cell, _cs_nof_prb) != 0) {
134 spdlog::error(
"Phy: Error setting UE MIB sync cell");
137 srsran_ue_sync_reset(&_mib_sync.ue_sync);
138 ret = srsran_ue_mib_sync_decode_prb(&_mib_sync, 40, bch_payload.data(), &new_cell.nof_ports, &sfn_offset, _cs_nof_prb);
144 if (new_cell.mbms_dedicated) {
145 srsran_pbch_mib_mbms_unpack(bch_payload.data(), &new_cell, &sfn,
nullptr,
148 srsran_pbch_mib_unpack(bch_payload.data(), &new_cell, &sfn);
150 sfn = (sfn + sfn_offset) % 1024;
153 "Phy: MIB Decoded. {} cell, Mode {}, PCI {}, PRB {}, Ports {}, CFO {} KHz, SFN "
154 "{}, sfn_offset {}\n",
155 new_cell.mbms_dedicated ?
"MBMS dedicated" :
"MBMS/Unicast mixed",
156 new_cell.frame_type != 0u ?
"TDD" :
"FDD", new_cell.id,
157 new_cell.nof_prb, new_cell.nof_ports, cfo / 1000, sfn, sfn_offset);
159 if (!srsran_cell_isvalid(&new_cell)) {
160 spdlog::error(
"SYNC: Detected invalid cell.\n");
165 _cell.mbsfn_prb = _cell.nof_prb;
167 if (srsran_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
168 spdlog::error(
"Phy: failed to set cell.\n");
171 if (srsran_ue_mib_set_cell(&_mib, cell()) != 0) {
172 spdlog::error(
"Phy: Error setting UE MIB cell");
179 spdlog::error(
"Phy: failed to receive MIB\n");
184 if (srsran_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
185 spdlog::error(
"Phy: failed to set cell.\n");
187 if (srsran_ue_mib_set_cell(&_mib, cell()) != 0) {
188 spdlog::error(
"Phy: Error setting UE MIB cell");
193 if (srsran_ue_cellsearch_init_multi_prb_cp(&_cell_search, 8,
receive_callback, _rx_channels,
194 this, _cs_nof_prb, _search_extended_cp) != 0) {
195 spdlog::error(
"Phy: error while initiating UE cell search\n");
198 srsran_ue_cellsearch_set_nof_valid_frames(&_cell_search, 4);
202 spdlog::error(
"Cannot init ue_sync");
206 if (srsran_ue_mib_sync_init_multi_prb(&_mib_sync,
receive_callback, _rx_channels,
this,
208 spdlog::error(
"Cannot init ue_mib_sync");
212 if (srsran_ue_mib_init(&_mib, _mib_buffer[0],
MAX_PRB) != 0) {
213 spdlog::error(
"Cannot init ue_mib");
221 return 1 == srsran_ue_sync_zerocopy(&_ue_sync, buffer, size);
225 if (sib13.nof_mbsfn_area_info > 1) {
226 spdlog::warn(
"SIB13 has {} MBSFN area info elements - only 1 supported", sib13.nof_mbsfn_area_info);
229 if (sib13.mbsfn_area_info_list[0].pmch_bandwidth != 0) {
230 _cell.mbsfn_prb = sib13.mbsfn_area_info_list[0].pmch_bandwidth;
233 if (sib13.nof_mbsfn_area_info > 0) {
237 if (sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info_is_r16) {
238 generate_mcch_table_r16(
240 static_cast<uint32_t
>(
241 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
245 static_cast<uint32_t
>(
246 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
249 std::stringstream ss;
252 ss << static_cast<int>(j) <<
"|";
254 spdlog::debug(
"MCCH table: {}", ss.str());
265 for (uint32_t i = 0; i <
_mcch.nof_pmch_info; i++) {
269 for (uint32_t j = 0; j <
_mcch.pmch_info_list[i].nof_mbms_session_info; j++) {
271 mtch_info.
lcid =
_mcch.pmch_info_list[i].mbms_session_info_list[j].lc_ch_id;
286 sprintf (tmgi,
"%06x%02x%02x%02x",
287 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[2] |
288 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[1] << 8 |
289 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[0] << 16 ,
290 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mcc[1] << 4 |
mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mcc[0],
291 (
_mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.nof_mnc_digits == 2 ? 0xF :
_mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mnc[2] ) << 4 |
_mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mcc[2] ,
292 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mnc[1] << 4 |
_mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.plmn_id.explicit_value.mnc[0]
294 mtch_info.
tmgi = tmgi;
296 mch_info.mtchs.push_back(mtch_info);
305 if (_cell.mbms_dedicated) {
309 unsigned sfn = tti / 10;
310 return (tti%10 == 0 || tti%10 == 5);
316 if (_cell.mbms_dedicated) {
318 return !is_cas_subframe(tti);
320 return !is_cas_subframe(tti) &&
321 (tti%10 == 1 || tti%10 == 2 || tti%10 == 3 || tti%10 == 6 || tti%10 == 7 || tti%10 == 8);
325 -> srsran_mbsfn_cfg_t {
326 srsran_mbsfn_cfg_t
cfg;
330 if (!_mcch_configured) {
336 uint32_t sfn = tti / 10;
337 uint8_t sf = tti % 10;
339 srsran::mbsfn_area_info_t& area_info = _sib13.mbsfn_area_info_list[0];
341 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
342 cfg.non_mbsfn_region_length = enum_to_number(area_info.non_mbsfn_region_len);
344 if (sfn % enum_to_number(area_info.mcch_cfg.mcch_repeat_period) == area_info.mcch_cfg.mcch_offset &&
345 _mcch_table[sf] == 1) {
348 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
352 }
else if (sfn % enum_to_number(area_info.mcch_cfg.mcch_repeat_period) == area_info.mcch_cfg.mcch_offset &&
354 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
358 if (_mch_configured) {
359 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
361 for (uint32_t i = 0; i < _mcch.nof_pmch_info; i++) {
362 unsigned fn_in_scheduling_period = sfn % enum_to_number(_mcch.pmch_info_list[i].mch_sched_period);
363 unsigned sf_idx = fn_in_scheduling_period * 10 + sf
364 - (fn_in_scheduling_period / 4)
367 spdlog::debug(
"i {}, tti {}, fn_in_ {}, sf_idx {}", i, tti, fn_in_scheduling_period, sf_idx);
369 if (sf_idx <= _mcch.pmch_info_list[i].sf_alloc_end) {
371 if ((i == 0 && fn_in_scheduling_period == 0 && sf == 1) ||
372 (i > 0 && _mcch.pmch_info_list[i-1].sf_alloc_end + 1 == sf_idx)) {
373 spdlog::debug(
"assigning sig_mcs {}, mch_idx is {}", area_info.mcch_cfg.sig_mcs, area);
374 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
376 spdlog::debug(
"assigning pmch_mcs {}, mch_idx is {}", _mcch.pmch_info_list[i].data_mcs, area);
377 cfg.mbsfn_mcs = _mcch.pmch_info_list[i].data_mcs;
const uint32_t kMaxBufferSamples
const uint32_t kMaxCellsToDiscover
const uint32_t kSfnOffset
const uint32_t kSubframesPerFrame
static auto receive_callback(void *obj, cf_t *data[SRSRAN_MAX_CHANNELS], uint32_t nsamples, srsran_timestamp_t *rx_time) -> int
constexpr unsigned int MAX_PRB
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.
std::function< int(cf_t *data[SRSRAN_MAX_CHANNELS], uint32_t nsamples, srsran_timestamp_t *rx_time)> get_samples_t
Definition of the callback function used to fetch samples from the SDR.
std::map< uint32_t, std::map< int, std::string > > _dests
const std::vector< mch_info_t > & mch_info()
void set_mch_scheduling_info(const srsran::sib13_t &sib13)
Set the values received in SIB13.
std::vector< mch_info_t > _mch_info
cf_t * _mib_buffer[SRSRAN_MAX_CHANNELS]
bool get_next_frame(cf_t **buffer, uint32_t size)
Get the sample data for the next subframe.
bool synchronize_subframe()
Synchronizes PSS/SSS and tries to deocode the MIB.
bool is_cas_subframe(unsigned tti)
srsran_ue_sync_t _ue_sync
bool init()
Initialize the underlying components.
bool cell_search()
Search for a cell.
virtual ~Phy()
Default destructor.
uint32_t _buffer_max_samples
srsran::mcch_msg_t & mcch()
bool is_mbsfn_subframe(unsigned tti)
void set_mbsfn_config(const srsran::mcch_msg_t &mcch)
Set MBSFN configuration values.
Phy(const libconfig::Config &cfg, get_samples_t cb, uint8_t cs_nof_prb, int8_t override_nof_prb, uint8_t rx_channels)
Default constructor.
static Config cfg
Global configuration object.