5G-MAG Reference Tools - MBMS Modem
Classes | Functions | Variables
main.cpp File Reference

Contains the program entry point, command line parameter handling, and the main runloop for data processing. More...

#include <argp.h>
#include <cstdlib>
#include <libconfig.h++>
#include "CasFrameProcessor.h"
#include "Gw.h"
#include "SdrReader.h"
#include "MbsfnFrameProcessor.h"
#include "MeasurementFileWriter.h"
#include "Phy.h"
#include "RestHandler.h"
#include "Rrc.h"
#include "Version.h"
#include "spdlog/async.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/syslog_sink.h"
#include "srsran/srsran.h"
#include "srsran/upper/pdcp.h"
#include "srsran/rlc/rlc.h"
#include "thread_pool.hpp"
Include dependency graph for main.cpp:

Go to the source code of this file.

Classes

struct  arguments
 Holds all options passed on the command line. More...
 

Functions

static void print_version (FILE *stream, struct argp_state *)
 Print the program version in MAJOR.MINOR.PATCH format. More...
 
static auto parse_opt (int key, char *arg, struct argp_state *state) -> error_t
 Parses the command line options into the arguments struct. More...
 
void set_params (const std::string &ant, unsigned fc, double g, unsigned sr, unsigned bw)
 Set new SDR parameters and initialize resynchronisation. More...
 
auto main (int argc, char **argv) -> int
 Main entry point for the program. More...
 

Variables

void(* argp_program_version_hook )(FILE *, struct argp_state *) = print_version
 
const char * argp_program_bug_address = "5G-MAG Reference Tools <reference-tools@5g-mag.com>"
 
static char doc [] = "5G-MAG-RT MBMS Modem Process"
 
static struct argp_option options []
 
static struct argp argp
 
static Config cfg
 Global configuration object. More...
 
static unsigned sample_rate = 7680000
 Sample rate of the SDR. More...
 
static unsigned search_sample_rate = 7680000
 Sample rate of the SDR. More...
 
static unsigned frequency = 667000000
 Center freqeuncy the SDR is tuned to. More...
 
static uint32_t bandwidth = 10000000
 Low pass filter bandwidth for the SDR. More...
 
static double gain = 0.9
 Overall system gain for the SDR. More...
 
static std::string antenna = "LNAW"
 Antenna input to be used. More...
 
static bool use_agc = false
 
static unsigned mbsfn_nof_prb = 0
 
static unsigned cas_nof_prb = 0
 
static bool restart = false
 Restart flag. More...
 

Detailed Description

Contains the program entry point, command line parameter handling, and the main runloop for data processing.

Definition in file main.cpp.

Function Documentation

◆ main()

auto main ( int  argc,
char **  argv 
) -> int

Main entry point for the program.

Parameters
argcCommand line agument count
argvCommand line arguments
Returns
0 on clean exit, -1 on failure

Definition at line 217 of file main.cpp.

217  {
218  struct arguments arguments;
219  /* Default values */
220  arguments.config_file = "/etc/5gmag-rt.conf";
221  arguments.sample_file = nullptr;
222  arguments.write_sample_file = nullptr;
223  argp_parse(&argp, argc, argv, 0, nullptr, &arguments);
224 
225  // Read and parse the configuration file
226  try {
227  cfg.readFile(arguments.config_file);
228  } catch(const FileIOException &fioex) {
229  spdlog::error("I/O error while reading config file at {}. Exiting.", arguments.config_file);
230  exit(1);
231  } catch(const ParseException &pex) {
232  spdlog::error("Config parse error at {}:{} - {}. Exiting.",
233  pex.getFile(), pex.getLine(), pex.getError());
234  exit(1);
235  }
236 
237  // Set up logging
238  std::string ident = "modem";
239  auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
240 
241  spdlog::set_level(
242  static_cast<spdlog::level::level_enum>(arguments.log_level));
243  spdlog::set_pattern("[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
244 
245  spdlog::set_default_logger(syslog_logger);
246  spdlog::info("5g-mag-rt modem v{}.{}.{} starting up", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
247 
248  // Init and tune the SDR
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);
252  SdrReader sdr(cfg, rx_channels);
254  sdr.enumerateDevices();
255  exit(0);
256  }
257 
258  std::string sdr_dev = "driver=lime";
259  cfg.lookupValue("modem.sdr.device_args", sdr_dev);
260  if (!sdr.init(sdr_dev, arguments.sample_file, arguments.write_sample_file)) {
261  spdlog::error("Failed to initialize I/Q data source.");
262  exit(1);
263  }
264 
265  cfg.lookupValue("modem.sdr.search_sample_rate_hz", sample_rate);
267 
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");
271  exit(1);
272  }
273  // We needed unsigned long long for correct parsing,
274  // but unsigned is required
275  if (center_frequency <= UINT_MAX) {
276  frequency = static_cast<unsigned>(center_frequency);
277  } else {
278  spdlog::error("Configured center_frequency_hz is {}, maximal value supported is {}.",
279  center_frequency, UINT_MAX);
280  exit(1);
281  }
282 
283 
284  cfg.lookupValue("modem.sdr.normalized_gain", gain);
285  cfg.lookupValue("modem.sdr.antenna", antenna);
286  cfg.lookupValue("modem.sdr.use_agc", use_agc);
287 
288  if (!sdr.tune(frequency, sample_rate, bandwidth, gain, antenna, use_agc)) {
289  spdlog::error("Failed to set initial center frequency. Exiting.");
290  exit(1);
291  }
292 
293  set_srsran_verbose_level(arguments.log_level <= 1 ? SRSRAN_VERBOSE_DEBUG : SRSRAN_VERBOSE_NONE);
294  srsran_use_standard_symbol_size(true);
295 
296  // Create a thread pool for the frame processors
297  unsigned thread_cnt = 4;
298  cfg.lookupValue("modem.phy.threads", thread_cnt);
299  int phy_prio = 10;
300  cfg.lookupValue("modem.phy.thread_priority_rt", phy_prio);
301  thread_pool pool{ thread_cnt + 1, phy_prio };
302 
303  // Elevate execution to real time scheduling
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);
307 
308  spdlog::info("Raising main thread to realtime scheduling priority {}", thread_param.sched_priority);
309 
310  int error = pthread_setschedparam(pthread_self(), SCHED_RR, &thread_param);
311  if (error != 0) {
312  spdlog::error("Cannot set main thread priority to realtime: {}. Thread will run at default priority.", strerror(error));
313  }
314 
315  bool enable_measurement_file = false;
316  cfg.lookupValue("modem.measurement_file.enabled", enable_measurement_file);
317  MeasurementFileWriter measurement_file(cfg);
318 
319  // Create the layer components: Phy, RLC, RRC and GW
320  Phy phy(
321  cfg,
322  std::bind(&SdrReader::get_samples, &sdr, _1, _2, _3), // NOLINT
323  arguments.file_bw ? arguments.file_bw * 5 : 25,
325  rx_channels);
326 
327  phy.init();
328 
329  srsran::pdcp pdcp(nullptr, "PDCP");
330  srsran::rlc rlc("RLC");
331  srsran::timer_handler timers;
332 
333  Rrc rrc(cfg, phy, rlc);
334  Gw gw(cfg, phy);
335  gw.init();
336 
337  rlc.init(&pdcp, &rrc, &timers, 0 /* RB_ID_SRB0 */);
338  pdcp.init(&rlc, &rrc, &gw);
339 
340  auto srs_level = srslog::basic_levels::none;
341  switch (arguments.srs_log_level) {
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;
347  }
348 
349  // Configure srsLTE logging
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);
358 
359 
360  state_t state = searching;
361 
362  // Create the RESTful API handler
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);
366  RestHandler rest_handler(cfg, uri, state, sdr, phy, set_params);
367 
368  // Initialize one CAS and thered_cnt MBSFN frame processors
369  CasFrameProcessor cas_processor(cfg, phy, rlc, rest_handler, rx_channels);
370  if (!cas_processor.init()) {
371  spdlog::error("Failed to create CAS processor. Exiting.");
372  exit(1);
373  }
374 
375  std::vector<MbsfnFrameProcessor*> mbsfn_processors;
376  for (int i = 0; i < thread_cnt; i++) {
377  auto p = new MbsfnFrameProcessor(cfg, rlc, phy, mac_log, rest_handler, rx_channels);
378  if (!p->init()) {
379  spdlog::error("Failed to create MBSFN processor. Exiting.");
380  exit(1);
381  }
382  mbsfn_processors.push_back(p);
383  }
384 
385  // Start receiving sample data
386  sdr.start();
387 
388  uint32_t tti = 0;
389 
390  uint32_t measurement_interval = 5;
391  cfg.lookupValue("modem.measurement_file.interval_secs", measurement_interval);
392  measurement_interval *= 1000;
393  uint32_t tick = 0;
394 
395  // Initial state: searching a cell
396  state = searching;
397 
398  // Start the main processing loop
399  for (;;) {
400  if (state == searching) {
401  if (restart) {
402  sdr.stop();
403  sample_rate = search_sample_rate; // sample rate for searching
405  sdr.start();
406  }
407 
408  // We're at the search sample rate, and there's no point in creating a sample file. Stop the sample writer, if enabled.
409  sdr.disableSampleFileWriting();
410 
411  // In searching state, clear the receive buffer and try to find a cell at the configured frequency and synchronize with it
412  restart = false;
413  sdr.clear_buffer();
414  bool cell_found = phy.cell_search();
415  if (cell_found) {
416  // A cell has been found. We now know the required number of PRB = bandwidth of the carrier. Set the approproiate
417  // sample rate...
418  cas_nof_prb = mbsfn_nof_prb = phy.nr_prb();
419 
421  // Samples files are recorded at a fixed sample rate that can be determined from the bandwidth command line argument.
422  // If we're decoding from file, do not readjust the rate to match the CAS PRBs, but stay at this rate and instead configure the
423  // PHY to decode a narrow CAS from a wider channel.
425  phy.set_nof_mbsfn_prb(mbsfn_nof_prb);
426  phy.set_cell();
427  } else {
428  // When decoding from the air, configure the SDR accordingly
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(),
431  phy.nr_prb() * 0.2);
432  sdr.stop();
433 
434  bandwidth = (cas_nof_prb * 200000) * 1.2;
435  sdr.tune(frequency, new_srate, bandwidth, gain, antenna, use_agc);
436 
437 
438  sdr.start();
439  }
440  spdlog::debug("Synchronizing subframe");
441  // ... and move to syncing state.
442  state = syncing;
443  } else {
444  sleep(1);
445  }
446  } else if (state == syncing) {
447  // In syncing state, we already know the cell we want to camp on, and the SDR is tuned to the required
448  // sample rate for its number of PRB / bandwidth. We now synchronize PSS/SSS and receive the MIB once again
449  // at this sample rate.
450  unsigned max_frames = 200;
451  bool sfn_sync = false;
452  while (!sfn_sync && max_frames-- > 0) {
453  sfn_sync = phy.synchronize_subframe();
454  }
455 
456  if (max_frames == 0 && !sfn_sync) {
457  // Failed. Back to square one: search state.
458  spdlog::warn("Synchronization failed. Going back to search state.");
459  state = searching;
460  sleep(1);
461  }
462 
463  if (sfn_sync) {
464  // We're locked on to the cell, and have succesfully received the MIB at the target sample rate.
465  spdlog::info("Decoded MIB at target sample rate, TTI is {}. Subframe synchronized.", phy.tti());
466 
467  // Set the cell parameters in the CAS processor
468  cas_processor.set_cell(phy.cell());
469 
470  for (int i = 0; i < thread_cnt; i++) {
471  mbsfn_processors[i]->unlock();
472  }
473 
474  // Get the initial TTI / subframe ID (= system frame number * 10 + subframe number)
475  tti = phy.tti();
476  // Reset the RRC
477  rrc.reset();
478 
479  // Ready to receive actual data. Go to processing state.
480  state = processing;
481 
482  // If sample file creation is enabled, start writing out samples now that we're at the target sample rate
483  sdr.enableSampleFileWriting();
484  }
485  } else { // processing
486  int mb_idx = 0;
487  while (state == processing) {
488  tti = (tti + 1) % 10240; // Clamp the TTI
489  unsigned sfn = tti / 10;
490  if (phy.is_cas_subframe(tti)) {
491  // Get the samples from the SDR interface, hand them to a CAS processor, and start it
492  // on a thread from the pool.
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)) {
497  // Set constellation diagram data and rx params for CAS in the REST API handler
498  rest_handler.add_cinr_value(ObjectPtr->cinr_db());
499  }
500  });
501 
502 
503  if (phy.nof_mbsfn_prb() != mbsfn_nof_prb)
504  {
505  // Handle the non-LTE bandwidths (6, 7 and 8 MHz). In these cases, CAS stays at the original bandwidth, but the MBSFN
506  // portion of the frames can be wider. We need to...
507 
508  mbsfn_nof_prb = phy.nof_mbsfn_prb();
509 
510  // ...adjust the SDR's sample rate to fit the wider MBSFN bandwidth...
511  unsigned new_srate = srsran_sampling_freq_hz(mbsfn_nof_prb);
512  spdlog::info("Setting sample rate {} Mhz for MBSFN with {} PRB / {} Mhz channel width", new_srate/1000000.0, mbsfn_nof_prb,
513  mbsfn_nof_prb * 0.2);
514  sdr.stop();
515 
516  bandwidth = (mbsfn_nof_prb * 200000) * 1.2;
517  sdr.tune(frequency, new_srate, bandwidth, gain, antenna, use_agc);
518 
519  // ... configure the PHY and CAS processor to decode a narrow CAS and wider MBSFN, and move back to syncing state
520  // after reconfiguring and restarting the SDR.
521  phy.set_cell();
522  cas_processor.set_cell(phy.cell());
523 
524  sdr.start();
525  spdlog::info("Synchronizing subframe after PRB extension");
526  state = syncing;
527  }
528  } else {
529  // Failed to receive data, or sync lost. Go back to searching state.
530  sdr.stop();
531  sample_rate = search_sample_rate; // sample rate for searching
533  sdr.start();
534  rrc.reset();
535  phy.reset();
536 
537  sleep(1);
538  state = searching;
539  }
540  } else {
541  // All other frames in FeMBMS dedicated mode are MBSFN frames.
542  spdlog::debug("sending tti {} to mbsfn proc {}", tti, mb_idx);
543 
544  // Get the samples from the SDR interface, hand them to an MNSFN processor, and start it
545  // on a thread from the pool. Getting the buffer pointer from the pool also locks this processor.
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)) {
548  // If data frm SIB1/SIB13 has been received in CAS, configure the processors accordingly
549  if (!mbsfn_processors[mb_idx]->mbsfn_configured()) {
550  srsran_scs_t scs = SRSRAN_SCS_15KHZ;
551  switch (phy.mbsfn_subcarrier_spacing()) {
552  case Phy::SubcarrierSpacing::df_15kHz: scs = SRSRAN_SCS_15KHZ; break;
553  case Phy::SubcarrierSpacing::df_7kHz5: scs = SRSRAN_SCS_7KHZ5; break;
554  case Phy::SubcarrierSpacing::df_1kHz25: scs = SRSRAN_SCS_1KHZ25; break;
555  }
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);
560  }
561  pool.push([ObjectPtr = mbsfn_processors[mb_idx], tti] {
562  ObjectPtr->process(tti);
563  });
564  } else {
565  // Nothing to do yet, we lack the data from SIB1/SIB13
566  // Discard the samples and unlock the processor.
567  mbsfn_processors[mb_idx]->unlock();
568  }
569  } else {
570  // Failed to receive data, or sync lost. Go back to searching state.
571  spdlog::warn("Synchronization lost while processing. Going back to searching state.");
572  sdr.stop();
573  sample_rate = search_sample_rate; // sample rate for searching
575  sdr.start();
576 
577  state = searching;
578  sleep(1);
579  rrc.reset();
580  phy.reset();
581  }
582  mb_idx = static_cast<int>((mb_idx + 1) % thread_cnt);
583  }
584 
585  tick++;
586  if (tick%measurement_interval == 0) {
587  // It's time to output rx info to the measurement file and to syslog.
588  // Collect the relevant info and write it out.
589  std::vector<std::string> cols;
590 
591  spdlog::info("CINR {:.2f} dB", rest_handler.cinr_db() );
592  cols.push_back(std::to_string(rest_handler.cinr_db()));
593 
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));
601 
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);
606 
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));
610 
611  auto mch_info = phy.mch_info();
612  int mch_idx = 0;
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 {}",
615  mch_idx,
616  mch.mcs,
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));
623 
624  int mtch_idx = 0;
625  std::for_each(std::begin(mch.mtchs), std::end(mch.mtchs), [&mtch_idx](Phy::mtch_info_t const& mtch) {
626  spdlog::info(" MTCH {}: LCID {}, TMGI 0x{}, {}",
627  mtch_idx,
628  mtch.lcid,
629  mtch.tmgi,
630  mtch.dest);
631  mtch_idx++;
632  });
633  mch_idx++;
634  });
635  spdlog::info("-----");
636  if (enable_measurement_file) {
637  measurement_file.WriteLogValues(cols);
638  }
639  }
640  }
641  }
642  }
643 
644  // Main loop ended by signal. Free the MBSFN processors, and bail.
645  for (int i = 0; i < thread_cnt; i++) {
646  delete( mbsfn_processors[i] );
647  }
648 exit:
649  return 0;
650 }
state_t
Definition: RestHandler.h:39
@ syncing
Definition: RestHandler.h:39
@ searching
Definition: RestHandler.h:39
@ processing
Definition: RestHandler.h:39
Frame processor for CAS subframes.
Network gateway component.
Definition: Gw.h:36
Frame processor for MBSFN subframes.
Writes measurement data / current reception parameters to a file.
The PHY component.
Definition: Phy.h:42
The RESTful API handler.
Definition: RestHandler.h:44
Simple RRC component between PHY and RLC.
Definition: Rrc.h:34
Interface to the SDR stick.
Definition: SdrReader.h:37
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.
Definition: SdrReader.cpp:315
static Config cfg
Global configuration object.
Definition: main.cpp:165
static std::string antenna
Antenna input to be used.
Definition: main.cpp:172
static unsigned mbsfn_nof_prb
Definition: main.cpp:175
static bool use_agc
Definition: main.cpp:173
static unsigned sample_rate
Sample rate of the SDR.
Definition: main.cpp:167
static bool restart
Restart flag.
Definition: main.cpp:186
static unsigned cas_nof_prb
Definition: main.cpp:176
static uint32_t bandwidth
Low pass filter bandwidth for the SDR.
Definition: main.cpp:170
static unsigned search_sample_rate
Sample rate of the SDR.
Definition: main.cpp:168
void set_params(const std::string &ant, unsigned fc, double g, unsigned sr, unsigned bw)
Set new SDR parameters and initialize resynchronisation.
Definition: main.cpp:198
static unsigned frequency
Center freqeuncy the SDR is tuned to.
Definition: main.cpp:169
static struct argp argp
Definition: main.cpp:153
static double gain
Overall system gain for the SDR.
Definition: main.cpp:171
std::vector< mtch_info_t > mtchs
Definition: Phy.h:172
Holds all options passed on the command line.
Definition: main.cpp:100
uint8_t file_bw
bandwidth of the sample file
Definition: main.cpp:106
const char * config_file
file path of the config file.
Definition: main.cpp:101
const char * write_sample_file
file path of the created sample file.
Definition: main.cpp:108
unsigned srs_log_level
srsLTE log level
Definition: main.cpp:103
int8_t override_nof_prb
ovride PRB number
Definition: main.cpp:104
unsigned log_level
log level
Definition: main.cpp:102
bool list_sdr_devices
Definition: main.cpp:109
const char * sample_file
file path of the sample file.
Definition: main.cpp:105

◆ parse_opt()

static auto parse_opt ( int  key,
char *  arg,
struct argp_state *  state 
) -> error_t
static

Parses the command line options into the arguments struct.

Definition at line 115 of file main.cpp.

115  {
116  auto arguments = static_cast<struct arguments *>(state->input);
117  switch (key) {
118  case 'c':
119  arguments->config_file = arg;
120  break;
121  case 'l':
122  arguments->log_level = static_cast<unsigned>(strtoul(arg, nullptr, 10));
123  break;
124  case 's':
126  static_cast<unsigned>(strtoul(arg, nullptr, 10));
127  break;
128  case 'f':
129  arguments->sample_file = arg;
130  break;
131  case 'w':
133  break;
134  case 'b':
135  arguments->file_bw = static_cast<uint8_t>(strtoul(arg, nullptr, 10));
136  break;
137  case 'p':
139  static_cast<int8_t>(strtol(arg, nullptr, 10));
140  break;
141  case 'd':
142  arguments->list_sdr_devices = true;
143  break;
144  case ARGP_KEY_ARG:
145  argp_usage(state);
146  break;
147  default:
148  return ARGP_ERR_UNKNOWN;
149  }
150  return 0;
151 }

◆ print_version()

void print_version ( FILE *  stream,
struct argp_state *  state 
)
static

Print the program version in MAJOR.MINOR.PATCH format.

Definition at line 159 of file main.cpp.

159  {
160  fprintf(stream, "%s.%s.%s\n", std::to_string(VERSION_MAJOR).c_str(),
161  std::to_string(VERSION_MINOR).c_str(),
162  std::to_string(VERSION_PATCH).c_str());
163 }

◆ set_params()

void set_params ( const std::string &  ant,
unsigned  fc,
double  g,
unsigned  sr,
unsigned  bw 
)

Set new SDR parameters and initialize resynchronisation.

This function is used by the RESTful API handler to modify the SDR params.

Parameters
antName of the antenna input (For LimeSDR Mini: LNAW, LNAL)
fcCenter frequency to tune to (in Hz)
gainTotal system gain to set [0..1]
srSample rate (in Hz)
bwLow pass filter bandwidth (in Hz)

Definition at line 198 of file main.cpp.

198  {
199  sample_rate = sr;
200  frequency = fc;
201  bandwidth = bw;
202  antenna = ant;
203  gain = g;
204  spdlog::info("RESTful API requesting new parameters: fc {}, bw {}, rate {}, gain {}, antenna {}",
206 
207  restart = true;
208 }

Variable Documentation

◆ antenna

std::string antenna = "LNAW"
static

Antenna input to be used.

Definition at line 172 of file main.cpp.

◆ argp

struct argp argp
static
Initial value:
= {options, parse_opt, nullptr, doc,
nullptr, nullptr, nullptr}
static struct argp_option options[]
Definition: main.cpp:66
static auto parse_opt(int key, char *arg, struct argp_state *state) -> error_t
Parses the command line options into the arguments struct.
Definition: main.cpp:115
static char doc[]
Definition: main.cpp:64

Definition at line 115 of file main.cpp.

◆ argp_program_bug_address

const char* argp_program_bug_address = "5G-MAG Reference Tools <reference-tools@5g-mag.com>"

Definition at line 63 of file main.cpp.

◆ argp_program_version_hook

void(* argp_program_version_hook) (FILE *, struct argp_state *) ( FILE *  ,
struct argp_state *   
) = print_version

Definition at line 62 of file main.cpp.

◆ bandwidth

uint32_t bandwidth = 10000000
static

Low pass filter bandwidth for the SDR.

Definition at line 170 of file main.cpp.

◆ cas_nof_prb

unsigned cas_nof_prb = 0
static

Definition at line 176 of file main.cpp.

◆ cfg

Config cfg
static

Global configuration object.

Definition at line 165 of file main.cpp.

◆ doc

char doc[] = "5G-MAG-RT MBMS Modem Process"
static

Definition at line 64 of file main.cpp.

◆ frequency

unsigned frequency = 667000000
static

Center freqeuncy the SDR is tuned to.

Definition at line 169 of file main.cpp.

◆ gain

double gain = 0.9
static

Overall system gain for the SDR.

Definition at line 171 of file main.cpp.

◆ mbsfn_nof_prb

unsigned mbsfn_nof_prb = 0
static

Definition at line 175 of file main.cpp.

◆ options

struct argp_option options[]
static
Initial value:
= {
{"config", 'c', "FILE", 0, "Configuration file (default: /etc/5gmag-rt.conf)", 0},
{"log-level", 'l', "LEVEL", 0,
"Log verbosity: 0 = trace, 1 = debug, 2 = info, 3 = warn, 4 = error, 5 = "
"critical, 6 = none. Default: 2.",
0},
{"srsran-log-level", 's', "LEVEL", 0,
"Log verbosity for srsran: 0 = debug, 1 = info, 2 = warn, 3 = error, 4 = "
"none, Default: 4.",
0},
{"sample-file", 'f', "FILE", 0,
"Sample file in 4 byte float interleaved format to read I/Q data from. If "
"present, the data from this file will be decoded instead of live SDR "
"data. The channel bandwith must be specified with the --file-bandwidth "
"flag, and the sample rate of the file must be suitable for this "
"bandwidth.",
0},
{"write-sample-file", 'w', "FILE", 0,
"Create a sample file in 4 byte float interleaved format containing the "
"raw received I/Q data.",
0},
{"file-bandwidth", 'b', "BANDWIDTH (MHz)", 0,
"If decoding data from a file, specify the channel bandwidth of the "
"recorded data in MHz here (e.g. 5)",
0},
{"override_nof_prb", 'p', "# PRB", 0,
"Override the number of PRB received in the MIB", 0},
{"sdr_devices", 'd', nullptr, 0,
"Prints a list of all available SDR devices", 0},
{nullptr, 0, nullptr, 0, nullptr, 0}}

Definition at line 64 of file main.cpp.

◆ restart

bool restart = false
static

Restart flag.

Setting this to true triggers resynchronization using the params set in the following parameters:

See also
sample_rate
frequency
bandwith
gain
antenna

Definition at line 186 of file main.cpp.

◆ sample_rate

unsigned sample_rate = 7680000
static

Sample rate of the SDR.

Definition at line 167 of file main.cpp.

◆ search_sample_rate

unsigned search_sample_rate = 7680000
static

Sample rate of the SDR.

Definition at line 168 of file main.cpp.

◆ use_agc

bool use_agc = false
static

Definition at line 173 of file main.cpp.