Main entry point for the program.
228 }
catch(
const FileIOException &fioex) {
231 }
catch(
const ParseException &pex) {
232 spdlog::error(
"Config parse error at {}:{} - {}. Exiting.",
233 pex.getFile(), pex.getLine(), pex.getError());
238 std::string ident =
"modem";
239 auto syslog_logger = spdlog::syslog_logger_mt(
"syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
243 spdlog::set_pattern(
"[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
245 spdlog::set_default_logger(syslog_logger);
246 spdlog::info(
"5g-mag-rt modem v{}.{}.{} starting up", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
249 auto rx_channels = 1;
250 cfg.lookupValue(
"modem.sdr.rx_channels", rx_channels);
251 spdlog::info(
"Initialising SDR with {} RX channel(s)", rx_channels);
254 sdr.enumerateDevices();
258 std::string sdr_dev =
"driver=lime";
259 cfg.lookupValue(
"modem.sdr.device_args", sdr_dev);
261 spdlog::error(
"Failed to initialize I/Q data source.");
268 unsigned long long center_frequency =
frequency;
269 if (!
cfg.lookupValue(
"modem.sdr.center_frequency_hz", center_frequency)) {
270 spdlog::error(
"Unable to parse center_frequency_hz - values must have a āLā character appended");
275 if (center_frequency <= UINT_MAX) {
276 frequency =
static_cast<unsigned>(center_frequency);
278 spdlog::error(
"Configured center_frequency_hz is {}, maximal value supported is {}.",
279 center_frequency, UINT_MAX);
284 cfg.lookupValue(
"modem.sdr.normalized_gain",
gain);
285 cfg.lookupValue(
"modem.sdr.antenna",
antenna);
286 cfg.lookupValue(
"modem.sdr.use_agc",
use_agc);
289 spdlog::error(
"Failed to set initial center frequency. Exiting.");
293 set_srsran_verbose_level(
arguments.
log_level <= 1 ? SRSRAN_VERBOSE_DEBUG : SRSRAN_VERBOSE_NONE);
294 srsran_use_standard_symbol_size(
true);
297 unsigned thread_cnt = 4;
298 cfg.lookupValue(
"modem.phy.threads", thread_cnt);
300 cfg.lookupValue(
"modem.phy.thread_priority_rt", phy_prio);
304 struct sched_param thread_param = {};
305 thread_param.sched_priority = 20;
306 cfg.lookupValue(
"modem.phy.main_thread_priority_rt", thread_param.sched_priority);
308 spdlog::info(
"Raising main thread to realtime scheduling priority {}", thread_param.sched_priority);
310 int error = pthread_setschedparam(pthread_self(), SCHED_RR, &thread_param);
312 spdlog::error(
"Cannot set main thread priority to realtime: {}. Thread will run at default priority.", strerror(error));
315 bool enable_measurement_file =
false;
316 cfg.lookupValue(
"modem.measurement_file.enabled", enable_measurement_file);
329 srsran::pdcp pdcp(
nullptr,
"PDCP");
330 srsran::rlc rlc(
"RLC");
331 srsran::timer_handler timers;
337 rlc.init(&pdcp, &rrc, &timers, 0 );
338 pdcp.init(&rlc, &rrc, &gw);
340 auto srs_level = srslog::basic_levels::none;
342 case 0: srs_level = srslog::basic_levels::debug;
break;
343 case 1: srs_level = srslog::basic_levels::info;
break;
344 case 2: srs_level = srslog::basic_levels::warning;
break;
345 case 3: srs_level = srslog::basic_levels::error;
break;
346 case 4: srs_level = srslog::basic_levels::none;
break;
350 auto& mac_log = srslog::fetch_basic_logger(
"MAC",
false);
351 mac_log.set_level(srs_level);
352 auto& phy_log = srslog::fetch_basic_logger(
"PHY",
false);
353 phy_log.set_level(srs_level);
354 auto& rlc_log = srslog::fetch_basic_logger(
"RLC",
false);
355 rlc_log.set_level(srs_level);
356 auto& asn1_log = srslog::fetch_basic_logger(
"ASN1",
false);
357 asn1_log.set_level(srs_level);
363 std::string uri =
"http://0.0.0.0:3010/modem-api/";
364 cfg.lookupValue(
"modem.restful_api.uri", uri);
365 spdlog::info(
"Starting RESTful API handler at {}", uri);
370 if (!cas_processor.init()) {
371 spdlog::error(
"Failed to create CAS processor. Exiting.");
375 std::vector<MbsfnFrameProcessor*> mbsfn_processors;
376 for (
int i = 0; i < thread_cnt; i++) {
379 spdlog::error(
"Failed to create MBSFN processor. Exiting.");
382 mbsfn_processors.push_back(p);
390 uint32_t measurement_interval = 5;
391 cfg.lookupValue(
"modem.measurement_file.interval_secs", measurement_interval);
392 measurement_interval *= 1000;
409 sdr.disableSampleFileWriting();
414 bool cell_found = phy.cell_search();
429 unsigned new_srate = srsran_sampling_freq_hz(
cas_nof_prb);
430 spdlog::info(
"Setting sample rate {} Mhz for {} PRB / {} Mhz channel width", new_srate/1000000.0, phy.nr_prb(),
440 spdlog::debug(
"Synchronizing subframe");
450 unsigned max_frames = 200;
451 bool sfn_sync =
false;
452 while (!sfn_sync && max_frames-- > 0) {
453 sfn_sync = phy.synchronize_subframe();
456 if (max_frames == 0 && !sfn_sync) {
458 spdlog::warn(
"Synchronization failed. Going back to search state.");
465 spdlog::info(
"Decoded MIB at target sample rate, TTI is {}. Subframe synchronized.", phy.tti());
468 cas_processor.set_cell(phy.cell());
470 for (
int i = 0; i < thread_cnt; i++) {
471 mbsfn_processors[i]->unlock();
483 sdr.enableSampleFileWriting();
488 tti = (tti + 1) % 10240;
489 unsigned sfn = tti / 10;
490 if (phy.is_cas_subframe(tti)) {
493 if (!
restart && phy.get_next_frame(cas_processor.rx_buffer(), cas_processor.rx_buffer_size())) {
494 spdlog::debug(
"sending tti {} to regular processor", tti);
495 pool.push([ObjectPtr = &cas_processor, tti, &rest_handler] {
496 if (ObjectPtr->process(tti)) {
498 rest_handler.add_cinr_value(ObjectPtr->cinr_db());
512 spdlog::info(
"Setting sample rate {} Mhz for MBSFN with {} PRB / {} Mhz channel width", new_srate/1000000.0,
mbsfn_nof_prb,
522 cas_processor.set_cell(phy.cell());
525 spdlog::info(
"Synchronizing subframe after PRB extension");
542 spdlog::debug(
"sending tti {} to mbsfn proc {}", tti, mb_idx);
546 if (!
restart && phy.get_next_frame(mbsfn_processors[mb_idx]->get_rx_buffer_and_lock(), mbsfn_processors[mb_idx]->rx_buffer_size())) {
547 if (phy.mcch_configured() && phy.is_mbsfn_subframe(tti)) {
549 if (!mbsfn_processors[mb_idx]->mbsfn_configured()) {
550 srsran_scs_t scs = SRSRAN_SCS_15KHZ;
551 switch (phy.mbsfn_subcarrier_spacing()) {
556 auto cell = phy.cell();
557 cell.nof_prb = cell.mbsfn_prb;
558 mbsfn_processors[mb_idx]->set_cell(cell);
559 mbsfn_processors[mb_idx]->configure_mbsfn(phy.mbsfn_area_id(), scs);
561 pool.push([ObjectPtr = mbsfn_processors[mb_idx], tti] {
562 ObjectPtr->process(tti);
567 mbsfn_processors[mb_idx]->unlock();
571 spdlog::warn(
"Synchronization lost while processing. Going back to searching state.");
582 mb_idx =
static_cast<int>((mb_idx + 1) % thread_cnt);
586 if (tick%measurement_interval == 0) {
589 std::vector<std::string> cols;
591 spdlog::info(
"CINR {:.2f} dB", rest_handler.cinr_db() );
592 cols.push_back(std::to_string(rest_handler.cinr_db()));
594 spdlog::info(
"PDSCH: MCS {}, BLER {}, BER {}",
595 rest_handler._pdsch.mcs,
596 ((rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0)),
597 rest_handler._pdsch.ber);
598 cols.push_back(std::to_string(rest_handler._pdsch.mcs));
599 cols.push_back(std::to_string(((rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0))));
600 cols.push_back(std::to_string(rest_handler._pdsch.ber));
602 spdlog::info(
"MCCH: MCS {}, BLER {}, BER {}",
603 rest_handler._mcch.mcs,
604 ((rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0)),
605 rest_handler._mcch.ber);
607 cols.push_back(std::to_string(rest_handler._mcch.mcs));
608 cols.push_back(std::to_string(((rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0))));
609 cols.push_back(std::to_string(rest_handler._mcch.ber));
611 auto mch_info = phy.mch_info();
613 std::for_each(std::begin(mch_info), std::end(mch_info), [&cols, &mch_idx, &rest_handler](
Phy::mch_info_t const& mch) {
614 spdlog::info(
"MCH {}: MCS {}, BLER {}, BER {}",
617 (rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0),
618 rest_handler._mch[mch_idx].ber);
619 cols.push_back(std::to_string(mch_idx));
620 cols.push_back(std::to_string(mch.
mcs));
621 cols.push_back(std::to_string((rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0)));
622 cols.push_back(std::to_string(rest_handler._mch[mch_idx].ber));
626 spdlog::info(
" MTCH {}: LCID {}, TMGI 0x{}, {}",
635 spdlog::info(
"-----");
636 if (enable_measurement_file) {
637 measurement_file.WriteLogValues(cols);
645 for (
int i = 0; i < thread_cnt; i++) {
646 delete( mbsfn_processors[i] );
Frame processor for CAS subframes.
Network gateway component.
Frame processor for MBSFN subframes.
Writes measurement data / current reception parameters to a file.
Simple RRC component between PHY and RLC.
Interface to the SDR stick.
int get_samples(cf_t *data[SRSRAN_MAX_CHANNELS], uint32_t nsamples, srsran_timestamp_t *rx_time)
Store nsamples count samples into the buffer at data.
static Config cfg
Global configuration object.
static std::string antenna
Antenna input to be used.
static unsigned mbsfn_nof_prb
static unsigned sample_rate
Sample rate of the SDR.
static bool restart
Restart flag.
static unsigned cas_nof_prb
static uint32_t bandwidth
Low pass filter bandwidth for the SDR.
static unsigned search_sample_rate
Sample rate of the SDR.
void set_params(const std::string &ant, unsigned fc, double g, unsigned sr, unsigned bw)
Set new SDR parameters and initialize resynchronisation.
static unsigned frequency
Center freqeuncy the SDR is tuned to.
static double gain
Overall system gain for the SDR.
std::vector< mtch_info_t > mtchs
Holds all options passed on the command line.
uint8_t file_bw
bandwidth of the sample file
const char * config_file
file path of the config file.
const char * write_sample_file
file path of the created sample file.
unsigned srs_log_level
srsLTE log level
int8_t override_nof_prb
ovride PRB number
unsigned log_level
log level
const char * sample_file
file path of the sample file.