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);
48 int8_t override_nof_prb, uint8_t rx_channels)
50 _sample_cb(std::move(std::move(cb))),
51 _cs_nof_prb(cs_nof_prb),
52 _override_nof_prb(override_nof_prb),
53 _rx_channels(rx_channels) {
66 int ret = srsran_ue_sync_zerocopy(&_ue_sync, _mib_buffer, _buffer_max_samples);
68 spdlog::error(
"SYNC: Error calling ue_sync_get_buffer.\n");
73 std::array<uint8_t, SRSRAN_BCH_PAYLOAD_LEN> bch_payload = {};
74 if (srsran_ue_sync_get_sfidx(&_ue_sync) == 0) {
77 srsran_ue_mib_decode(&_mib, bch_payload.data(),
nullptr, &sfn_offset);
80 if (_cell.mbms_dedicated) {
81 srsran_pbch_mib_mbms_unpack(bch_payload.data(), &_cell, &sfn,
nullptr,
85 srsran_pbch_mib_unpack(bch_payload.data(), &_cell, &sfn);
86 sfn = (sfn + sfn_offset) %
kMaxSfn;
97 std::array<srsran_ue_cellsearch_result_t, kMaxCellsToDiscover> found_cells = {0};
99 uint32_t max_peak_cell = 0;
100 int ret = srsran_ue_cellsearch_scan(&_cell_search, found_cells.data(), &max_peak_cell);
102 spdlog::error(
"Phy: Error decoding MIB: Error searching PSS\n");
106 spdlog::error(
"Phy: Could not find any cell in this frequency\n");
110 srsran_cell_t new_cell = {};
111 new_cell.id = found_cells.at(max_peak_cell).cell_id;
112 new_cell.cp = found_cells.at(max_peak_cell).cp;
113 new_cell.frame_type = found_cells.at(max_peak_cell).frame_type;
114 float cfo = found_cells.at(max_peak_cell).cfo;
116 spdlog::info(
"Phy: PSS/SSS detected: Mode {}, PCI {}, CFO {} KHz, CP {}",
117 new_cell.frame_type != 0U ?
"TDD" :
"FDD", new_cell.id,
118 cfo / 1000, srsran_cp_string(new_cell.cp));
122 std::array<uint8_t, SRSRAN_BCH_PAYLOAD_LEN> bch_payload = {};
127 new_cell.mbms_dedicated =
true;
128 if (srsran_ue_mib_sync_set_cell_prb(&_mib_sync, new_cell, _cs_nof_prb) != 0) {
129 spdlog::error(
"Phy: Error setting UE MIB sync cell");
132 srsran_ue_sync_reset(&_mib_sync.ue_sync);
133 ret = srsran_ue_mib_sync_decode_prb(&_mib_sync,
kMaxFramesTimeout, bch_payload.data(), &new_cell.nof_ports, &sfn_offset, _cs_nof_prb);
137 new_cell.mbms_dedicated =
false;
138 if (srsran_ue_mib_sync_set_cell_prb(&_mib_sync, new_cell, _cs_nof_prb) != 0) {
139 spdlog::error(
"Phy: Error setting UE MIB sync cell");
142 srsran_ue_sync_reset(&_mib_sync.ue_sync);
143 ret = srsran_ue_mib_sync_decode_prb(&_mib_sync,
kMaxFramesTimeout, bch_payload.data(), &new_cell.nof_ports, &sfn_offset, _cs_nof_prb);
149 if (new_cell.mbms_dedicated) {
150 srsran_pbch_mib_mbms_unpack(bch_payload.data(), &new_cell, &sfn,
nullptr,
153 srsran_pbch_mib_unpack(bch_payload.data(), &new_cell, &sfn);
155 sfn = (sfn + sfn_offset) % 1024;
158 "Phy: MIB Decoded. {} cell, Mode {}, PCI {}, PRB {}, Ports {}, CFO {} KHz, SFN "
159 "{}, sfn_offset {}\n",
160 new_cell.mbms_dedicated ?
"MBMS dedicated" :
"MBMS/Unicast mixed",
161 new_cell.frame_type != 0u ?
"TDD" :
"FDD", new_cell.id,
162 new_cell.nof_prb, new_cell.nof_ports, cfo / 1000, sfn, sfn_offset);
164 if (!srsran_cell_isvalid(&new_cell)) {
165 spdlog::error(
"SYNC: Detected invalid cell.\n");
170 _cell.mbsfn_prb = _cell.nof_prb;
172 if (srsran_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
173 spdlog::error(
"Phy: failed to set cell.\n");
176 if (srsran_ue_mib_set_cell(&_mib, cell()) != 0) {
177 spdlog::error(
"Phy: Error setting UE MIB cell");
184 spdlog::error(
"Phy: failed to receive MIB\n");
189 if (srsran_ue_sync_set_cell(&_ue_sync, cell()) != 0) {
190 spdlog::error(
"Phy: failed to set cell.\n");
192 if (srsran_ue_mib_set_cell(&_mib, cell()) != 0) {
193 spdlog::error(
"Phy: Error setting UE MIB cell");
199 this, _cs_nof_prb, _search_extended_cp) != 0) {
200 spdlog::error(
"Phy: error while initiating UE cell search\n");
203 srsran_ue_cellsearch_set_nof_valid_frames(&_cell_search,
kMaxValidFrames);
207 spdlog::error(
"Cannot init ue_sync");
211 if (srsran_ue_mib_sync_init_multi_prb(&_mib_sync,
receive_callback, _rx_channels,
this,
213 spdlog::error(
"Cannot init ue_mib_sync");
217 if (srsran_ue_mib_init(&_mib, _mib_buffer[0],
MAX_PRB) != 0) {
218 spdlog::error(
"Cannot init ue_mib");
226 return 1 == srsran_ue_sync_zerocopy(&_ue_sync, buffer, size);
230 if (sib13.nof_mbsfn_area_info > 1) {
231 spdlog::warn(
"SIB13 has {} MBSFN area info elements - only 1 supported", sib13.nof_mbsfn_area_info);
234 if (sib13.mbsfn_area_info_list[0].pmch_bandwidth != 0) {
235 _cell.mbsfn_prb = sib13.mbsfn_area_info_list[0].pmch_bandwidth;
238 if (sib13.nof_mbsfn_area_info > 0) {
242 if (sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info_is_r16) {
243 generate_mcch_table_r16(
245 static_cast<uint32_t
>(
246 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
250 static_cast<uint32_t
>(
251 sib13.mbsfn_area_info_list[0].mcch_cfg.sf_alloc_info));
254 std::stringstream ss;
257 ss << static_cast<int>(j) <<
"|";
259 spdlog::debug(
"MCCH table: {}", ss.str());
270 for (uint32_t i = 0; i <
_mcch.nof_pmch_info; i++) {
274 for (uint32_t j = 0; j <
_mcch.pmch_info_list[i].nof_mbms_session_info; j++) {
276 mtch_info.
lcid =
_mcch.pmch_info_list[i].mbms_session_info_list[j].lc_ch_id;
291 sprintf (tmgi,
"%06x%02x%02x%02x",
292 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[2] |
293 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[1] << 8 |
294 _mcch.pmch_info_list[i].mbms_session_info_list[j].tmgi.serviced_id[0] << 16 ,
295 _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],
296 (
_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] ,
297 _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]
299 mtch_info.
tmgi = tmgi;
301 mch_info.mtchs.push_back(mtch_info);
310 if (_cell.mbms_dedicated) {
314 unsigned sfn = tti / 10;
315 return (tti%10 == 0 || tti%10 == 5);
321 if (_cell.mbms_dedicated) {
323 return !is_cas_subframe(tti);
325 return !is_cas_subframe(tti) &&
326 (tti%10 == 1 || tti%10 == 2 || tti%10 == 3 || tti%10 == 6 || tti%10 == 7 || tti%10 == 8);
330 -> srsran_mbsfn_cfg_t {
331 srsran_mbsfn_cfg_t
cfg;
335 if (!_mcch_configured) {
341 uint32_t sfn = tti / 10;
342 uint8_t sf = tti % 10;
344 srsran::mbsfn_area_info_t& area_info = _sib13.mbsfn_area_info_list[0];
346 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
347 cfg.non_mbsfn_region_length = enum_to_number(area_info.non_mbsfn_region_len);
349 if (sfn % enum_to_number(area_info.mcch_cfg.mcch_repeat_period) == area_info.mcch_cfg.mcch_offset &&
350 _mcch_table[sf] == 1) {
353 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
357 }
else if (sfn % enum_to_number(area_info.mcch_cfg.mcch_repeat_period) == area_info.mcch_cfg.mcch_offset &&
359 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
363 if (_mch_configured) {
364 cfg.mbsfn_area_id = area_info.mbsfn_area_id;
366 for (uint32_t i = 0; i < _mcch.nof_pmch_info; i++) {
367 unsigned fn_in_scheduling_period = sfn % enum_to_number(_mcch.pmch_info_list[i].mch_sched_period);
368 unsigned sf_idx = fn_in_scheduling_period * 10 + sf
369 - (fn_in_scheduling_period / 4)
372 spdlog::debug(
"i {}, tti {}, fn_in_ {}, sf_idx {}", i, tti, fn_in_scheduling_period, sf_idx);
374 if (sf_idx <= _mcch.pmch_info_list[i].sf_alloc_end) {
376 if ((i == 0 && fn_in_scheduling_period == 0 && sf == 1) ||
377 (i > 0 && _mcch.pmch_info_list[i-1].sf_alloc_end + 1 == sf_idx)) {
378 spdlog::debug(
"assigning sig_mcs {}, mch_idx is {}", area_info.mcch_cfg.sig_mcs, area);
379 cfg.mbsfn_mcs = enum_to_number(area_info.mcch_cfg.sig_mcs);
381 spdlog::debug(
"assigning pmch_mcs {}, mch_idx is {}", _mcch.pmch_info_list[i].data_mcs, area);
382 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 kMaxScannedFrames
const uint32_t kMaxValidFrames
const uint32_t kSubframesPerFrame
const uint32_t kMaxFramesTimeout
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.