Main entry point for the program.
235 }
catch(
const FileIOException &fioex) {
238 }
catch(
const ParseException &pex) {
239 spdlog::error(
"Config parse error at {}:{} - {}. Exiting.",
240 pex.getFile(), pex.getLine(), pex.getError());
245 std::string ident =
"modem";
246 auto syslog_logger = spdlog::syslog_logger_mt(
"syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
250 spdlog::set_pattern(
"[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
252 spdlog::set_default_logger(syslog_logger);
253 spdlog::info(
"5g-mag-rt modem v{}.{}.{} starting up", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
256 auto rx_channels = 1;
257 cfg.lookupValue(
"modem.sdr.rx_channels", rx_channels);
258 spdlog::info(
"Initialising SDR with {} RX channel(s)", rx_channels);
261 sdr.enumerateDevices();
265 std::string sdr_dev =
"driver=lime";
266 cfg.lookupValue(
"modem.sdr.device_args", sdr_dev);
268 spdlog::error(
"Failed to initialize I/Q data source.");
275 unsigned long long center_frequency =
frequency;
276 if (!
cfg.lookupValue(
"modem.sdr.center_frequency_hz", center_frequency)) {
277 spdlog::error(
"Unable to parse center_frequency_hz - values must have a ‘L’ character appended");
282 if (center_frequency <= UINT_MAX) {
283 frequency =
static_cast<unsigned>(center_frequency);
285 spdlog::error(
"Configured center_frequency_hz is {}, maximal value supported is {}.",
286 center_frequency, UINT_MAX);
291 cfg.lookupValue(
"modem.sdr.normalized_gain",
gain);
292 cfg.lookupValue(
"modem.sdr.antenna",
antenna);
293 cfg.lookupValue(
"modem.sdr.use_agc",
use_agc);
296 spdlog::error(
"Failed to set initial center frequency. Exiting.");
300 set_srsran_verbose_level(
arguments.
log_level <= 1 ? SRSRAN_VERBOSE_DEBUG : SRSRAN_VERBOSE_NONE);
301 srsran_use_standard_symbol_size(
true);
304 unsigned thread_cnt = 4;
305 cfg.lookupValue(
"modem.phy.threads", thread_cnt);
307 cfg.lookupValue(
"modem.phy.thread_priority_rt", phy_prio);
311 struct sched_param thread_param = {};
312 thread_param.sched_priority = 20;
313 cfg.lookupValue(
"modem.phy.main_thread_priority_rt", thread_param.sched_priority);
315 spdlog::info(
"Raising main thread to realtime scheduling priority {}", thread_param.sched_priority);
317 int error = pthread_setschedparam(pthread_self(), SCHED_RR, &thread_param);
319 spdlog::error(
"Cannot set main thread priority to realtime: {}. Thread will run at default priority.", strerror(error));
322 bool enable_measurement_file =
false;
323 cfg.lookupValue(
"modem.measurement_file.enabled", enable_measurement_file);
336 srsran::pdcp pdcp(
nullptr,
"PDCP");
337 srsran::rlc rlc(
"RLC");
338 srsran::timer_handler timers;
344 rlc.init(&pdcp, &rrc, &timers, 0 );
345 pdcp.init(&rlc, &rrc, &gw);
347 auto srs_level = srslog::basic_levels::none;
349 case 0: srs_level = srslog::basic_levels::debug;
break;
350 case 1: srs_level = srslog::basic_levels::info;
break;
351 case 2: srs_level = srslog::basic_levels::warning;
break;
352 case 3: srs_level = srslog::basic_levels::error;
break;
353 case 4: srs_level = srslog::basic_levels::none;
break;
357 auto& mac_log = srslog::fetch_basic_logger(
"MAC",
false);
358 mac_log.set_level(srs_level);
359 auto& phy_log = srslog::fetch_basic_logger(
"PHY",
false);
360 phy_log.set_level(srs_level);
361 auto& rlc_log = srslog::fetch_basic_logger(
"RLC",
false);
362 rlc_log.set_level(srs_level);
363 auto& asn1_log = srslog::fetch_basic_logger(
"ASN1",
false);
364 asn1_log.set_level(srs_level);
370 std::string uri =
"http://0.0.0.0:3010/modem-api/";
371 cfg.lookupValue(
"modem.restful_api.uri", uri);
372 spdlog::info(
"Starting RESTful API handler at {}", uri);
377 if (!cas_processor.init()) {
378 spdlog::error(
"Failed to create CAS processor. Exiting.");
383 rest_handler.set_cas_processor(&cas_processor);
385 std::vector<MbsfnFrameProcessor*> mbsfn_processors;
386 for (
int i = 0; i < thread_cnt; i++) {
389 spdlog::error(
"Failed to create MBSFN processor. Exiting.");
392 mbsfn_processors.push_back(p);
395 rest_handler.start();
400 uint32_t mch_bler_global = 0;
401 uint32_t mcch_bler_global = 0;
402 uint32_t pdsch_bler_global = 0;
403 uint32_t mch_total_global = 0;
404 uint32_t mcch_total_global = 0;
405 uint32_t pdsch_total_global = 0;
408 uint32_t sync_losses = 0;
409 uint32_t lost_subframes = 0;
410 uint32_t measurements = 0.0f;
414 float measurement_interval_f = 5;
415 cfg.lookupValue(
"modem.measurement_file.interval_secs", measurement_interval_f);
416 uint32_t measurement_interval = measurement_interval_f * 1000;
427 tti = (tti + 1) % 10240;
428 if (phy.is_cas_subframe(tti)) {
431 if (!
restart && phy.get_next_frame(cas_processor.get_rx_buffer_and_lock(), cas_processor.rx_buffer_size())) {
432 spdlog::debug(
"sending tti {} to regular processor", tti);
433 pool.push([ObjectPtr = &cas_processor, tti, &rest_handler] {
434 if (ObjectPtr->process(tti)) {
436 rest_handler.add_cinr_value(ObjectPtr->cinr_db());
450 spdlog::info(
"Setting sample rate {} Mhz for MBSFN with {} PRB / {} Mhz channel width", new_srate/1000000.0,
mbsfn_nof_prb,
460 cas_processor.set_cell(phy.cell());
463 spdlog::info(
"Synchronizing subframe after PRB extension");
468 spdlog::warn(
"Synchronization lost while processing. Going back to searching state.");
474 spdlog::debug(
"sending tti {} to mbsfn proc {}", tti, mb_idx);
478 if (!
restart && phy.get_next_frame(mbsfn_processors[mb_idx]->get_rx_buffer_and_lock(), mbsfn_processors[mb_idx]->rx_buffer_size())) {
479 if (phy.mcch_configured() && phy.is_mbsfn_subframe(tti)) {
481 if (!mbsfn_processors[mb_idx]->mbsfn_configured()) {
482 srsran_scs_t scs = SRSRAN_SCS_15KHZ;
483 switch (phy.mbsfn_subcarrier_spacing()) {
488 auto cell = phy.cell();
489 cell.nof_prb = cell.mbsfn_prb;
490 mbsfn_processors[mb_idx]->set_cell(cell);
491 mbsfn_processors[mb_idx]->configure_mbsfn(phy.mbsfn_area_id(), scs);
493 pool.push([ObjectPtr = mbsfn_processors[mb_idx], tti] {
494 ObjectPtr->process(tti);
499 mbsfn_processors[mb_idx]->unlock();
503 spdlog::warn(
"Synchronization lost while processing. Going back to searching state.");
507 mb_idx =
static_cast<int>((mb_idx + 1) % thread_cnt);
526 bool cell_found = phy.cell_search();
541 unsigned new_srate = srsran_sampling_freq_hz(
cas_nof_prb);
542 spdlog::info(
"Setting sample rate {} Mhz for {} PRB / {} Mhz channel width", new_srate/1000000.0, phy.nr_prb(),
552 spdlog::debug(
"Synchronizing subframe");
569 bool sfn_sync =
false;
570 sfn_sync = phy.synchronize_subframe();
574 lost_subframes += (((phy.tti() < tti) * 10240 + phy.tti())-tti) * cas_processor.is_started() ;
575 spdlog::info(
"Decoded MIB at target sample rate, TTI is {}. Subframe synchronized, sync lost in TTI {}, {} subframes lost, {} total subframe lost, sync losses {}.", phy.tti(), tti, (((phy.tti() < tti) * 10240 + phy.tti())-tti) * cas_processor.is_started(), lost_subframes, sync_losses);
578 cas_processor.set_cell(phy.cell());
580 for (
int i = 0; i < thread_cnt; i++) {
581 mbsfn_processors[i]->unlock();
583 cas_processor.unlock();
594 sdr.enableSampleFileWriting();
604 if (tick%measurement_interval == 0) {
607 std::vector<std::string> cols;
611 spdlog::info(
"CINR {:.2f} dB", rest_handler.cinr_db() );
612 cols.push_back(std::to_string((
float)rest_handler.cinr_db()));
615 cas_processor.lock();
617 spdlog::info(
"PDSCH: MCS {}, BLER {}",
618 rest_handler._pdsch.mcs,
619 ((rest_handler._pdsch.errors > 0 && rest_handler._pdsch.total > 0) ? (rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0) : 0));
621 cols.push_back(std::to_string(rest_handler._pdsch.mcs));
622 cols.push_back(std::to_string(((rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0))));
624 pdsch_bler_global += rest_handler._pdsch.errors;
625 pdsch_total_global += rest_handler._pdsch.total;
626 rest_handler._pdsch.errors = 0;
627 rest_handler._pdsch.total = 0;
629 cas_processor.unlock();
632 for (
int i = 0; i < thread_cnt; i++) {
633 mbsfn_processors[i]->lock();
635 spdlog::info(
"MCCH: MCS {}, BLER {}",
636 rest_handler._mcch.mcs,
637 ((rest_handler._mcch.errors > 0 && rest_handler._mcch.total > 0) ? (rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0) : 0));
639 cols.push_back(std::to_string(rest_handler._mcch.mcs));
640 cols.push_back(std::to_string(((rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0))));
642 cols.push_back(std::to_string(tti));
643 cols.emplace_back(std::string(
""));
644 cols.push_back(std::to_string(lost_subframes));
646 auto mch_info = phy.mch_info();
648 std::for_each(std::begin(mch_info), std::end(mch_info), [&cols, &mch_idx, &rest_handler, &mch_bler_global, &mch_total_global](
Phy::mch_info_t const& mch) {
650 spdlog::info(
"MCH {}: MCS {}, BLER {}",
653 ((rest_handler._mch[mch_idx].errors > 0 && rest_handler._mch[mch_idx].total > 0) ? (rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0) : 0));
655 cols.push_back(std::to_string(mch_idx));
656 cols.push_back(std::to_string(mch.
mcs));
657 cols.push_back(std::to_string((rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0)));
660 std::for_each(std::begin(mch.
mtchs), std::end(mch.
mtchs), [&mtch_idx, &mch_bler_global, &mch_total_global](
Phy::mtch_info_t const& mtch) {
661 spdlog::info(
" MTCH {}: LCID {}, TMGI 0x{}, {}",
669 mch_bler_global += rest_handler._mch[mch_idx].errors;
670 mch_total_global += rest_handler._mch[mch_idx].total;
671 rest_handler._mch[mch_idx].errors = 0;
672 rest_handler._mch[mch_idx].total = 0;
676 mcch_bler_global += rest_handler._mcch.errors;
677 mcch_total_global += rest_handler._mcch.total;
678 rest_handler._mcch.errors = 0;
679 rest_handler._mcch.total = 0;
681 for (
int i = 0; i < thread_cnt; i++) {
682 mbsfn_processors[i]->unlock();
685 cols.emplace_back(std::string(
"NOT SYNC - SYNCING..."));
686 cols.emplace_back(std::string(
"nan"));
687 cols.emplace_back(std::string(
"nan"));
688 cols.emplace_back(std::string(
"nan"));
689 cols.emplace_back(std::string(
"nan"));
690 cols.emplace_back(std::string(
"nan"));
691 cols.push_back(std::to_string(sync_losses));
692 cols.push_back(std::to_string(lost_subframes));
693 cols.emplace_back(std::string(
"nan"));
694 cols.emplace_back(std::string(
"nan"));
695 cols.emplace_back(std::string(
"nan"));
698 cols.emplace_back(std::string(
"SEARCHING FOR A CELL..."));
699 cols.emplace_back(std::string(
"nan"));
700 cols.emplace_back(std::string(
"nan"));
701 cols.emplace_back(std::string(
"nan"));
702 cols.emplace_back(std::string(
"nan"));
703 cols.emplace_back(std::string(
"nan"));
704 cols.emplace_back(std::string(
""));
705 cols.push_back(std::to_string(lost_subframes));
706 cols.emplace_back(std::string(
"nan"));
707 cols.emplace_back(std::string(
"nan"));
708 cols.emplace_back(std::string(
"nan"));
711 if (enable_measurement_file) {
712 measurement_file.WriteLogValues(cols);
716 spdlog::info(
"------ Global statistics ------ \n\t\tMCH BLER {}, \n\t\tMCH TOTAL ERRORS {}, \n\t\tMCCH BLER: {}, \n\t\tPDSCH BLER: {}, \n\t\tSYNC LOSSES: {}, \n\t\tSF PROCESSED: {}",
717 ((mch_bler_global > 0 && mch_total_global > 0) ? (mch_bler_global * 1.0) / (mch_total_global * 1.0) : 0),
719 ((mcch_bler_global > 0 && mcch_total_global > 0) ? (mcch_bler_global * 1.0) / (mcch_total_global * 1.0) : 0),
720 ((pdsch_bler_global > 0 && pdsch_total_global > 0) ? (pdsch_bler_global * 1.0) / (pdsch_total_global * 1.0) : 0),
724 spdlog::info(
"Total subframe lost {}, sync losses {}.", lost_subframes, sync_losses);
730 for (
int i = 0; i < thread_cnt; i++) {
731 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.