OBECA Receive Process
main.cpp
Go to the documentation of this file.
1 // OBECA - Open Broadcast Edge Cache Appliance
2 // Receive Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
15 //
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
31 #include <argp.h>
32 
33 #include <cstdlib>
34 #include <libconfig.h++>
35 
36 #include "CasFrameProcessor.h"
37 #include "Gw.h"
38 #include "LimeSdrReader.h"
39 #include "MbsfnFrameProcessor.h"
40 #include "MeasurementFileWriter.h"
41 #include "Phy.h"
42 #include "RestHandler.h"
43 #include "Rrc.h"
44 #include "Version.h"
45 #include "spdlog/async.h"
46 #include "spdlog/spdlog.h"
47 #include "spdlog/sinks/syslog_sink.h"
48 #include "srslte/srslte.h"
49 #include "srslte/upper/pdcp.h"
50 #include "srslte/upper/rlc.h"
51 #include "thread_pool.hpp"
52 
53 using libconfig::Config;
54 using libconfig::FileIOException;
55 using libconfig::ParseException;
56 
57 using std::placeholders::_1;
58 using std::placeholders::_2;
59 using std::placeholders::_3;
60 
61 static void print_version(FILE *stream, struct argp_state *state);
62 void (*argp_program_version_hook)(FILE *, struct argp_state *) = print_version;
63 const char *argp_program_bug_address = "Austrian Broadcasting Services <obeca@ors.at>";
64 static char doc[] = "OBECA Receive Process"; // NOLINT
65 
66 static struct argp_option options[] = { // NOLINT
67  {"config", 'c', "FILE", 0, "Configuration file (default: /etc/rp.conf)", 0},
68  {"log-level", 'l', "LEVEL", 0,
69  "Log verbosity: 0 = trace, 1 = debug, 2 = info, 3 = warn, 4 = error, 5 = "
70  "critical, 6 = none. Default: 2.",
71  0},
72  {"srslte-log-level", 's', "LEVEL", 0,
73  "Log verbosity for srslte: 0 = debug, 1 = info, 2 = warn, 3 = error, 4 = "
74  "none, Default: 4.",
75  0},
76  {"sample-file", 'f', "FILE", 0,
77  "Sample file in 4 byte float interleaved format to read I/Q data from. If "
78  "present, the data from this file will be decoded instead of live SDR "
79  "data. The channel bandwith must be specified with the --file-bandwidth "
80  "flag, and the sample rate of the file must be suitable for this "
81  "bandwidth.",
82  0},
83  {"write-sample-file", 'w', "FILE", 0,
84  "Create a sample file in 4 byte float interleaved format containing the "
85  "raw received I/Q data.",
86  0},
87  {"file-bandwidth", 'b', "BANDWIDTH (MHz)", 0,
88  "If decoding data from a file, specify the channel bandwidth of the "
89  "recorded data in MHz here (e.g. 5)",
90  0},
91  {"override_nof_prb", 'p', "# PRB", 0,
92  "Override the number of PRB received in the MIB", 0},
93  {nullptr, 0, nullptr, 0, nullptr, 0}};
94 
98 struct arguments {
99  const char *config_file = {};
100  unsigned log_level = 2;
101  unsigned srs_log_level = 4;
102  int8_t override_nof_prb = -1;
103  const char *sample_file = {};
104  uint8_t file_bw = 5;
105  const char
107 };
108 
112 static auto parse_opt(int key, char *arg, struct argp_state *state) -> error_t {
113  auto arguments = static_cast<struct arguments *>(state->input);
114  switch (key) {
115  case 'c':
116  arguments->config_file = arg;
117  break;
118  case 'l':
119  arguments->log_level = static_cast<unsigned>(strtoul(arg, nullptr, 10));
120  break;
121  case 's':
123  static_cast<unsigned>(strtoul(arg, nullptr, 10));
124  break;
125  case 'f':
126  arguments->sample_file = arg;
127  break;
128  case 'w':
130  break;
131  case 'b':
132  arguments->file_bw = static_cast<uint8_t>(strtoul(arg, nullptr, 10));
133  break;
134  case 'p':
136  static_cast<int8_t>(strtol(arg, nullptr, 10));
137  break;
138  case ARGP_KEY_ARG:
139  argp_usage(state);
140  break;
141  default:
142  return ARGP_ERR_UNKNOWN;
143  }
144  return 0;
145 }
146 
147 static struct argp argp = {options, parse_opt, nullptr, doc,
148  nullptr, nullptr, nullptr};
149 
153 void print_version(FILE *stream, struct argp_state * /*state*/) {
154  fprintf(stream, "%s.%s.%s\n", std::to_string(VERSION_MAJOR).c_str(),
155  std::to_string(VERSION_MINOR).c_str(),
156  std::to_string(VERSION_PATCH).c_str());
157 }
158 
159 static Config cfg;
161 static unsigned sample_rate = 7680000;
162 static unsigned search_sample_rate = 7680000;
163 static unsigned frequency = 667000000;
164 static uint32_t bandwidth = 10000000;
165 static double gain = 0.9;
166 static std::string antenna = "LNAW";
168 static unsigned mbsfn_nof_prb = 0;
169 static unsigned cas_nof_prb = 0;
170 
179 static bool restart = false;
180 
191 void set_params(const std::string& ant, unsigned fc, double g, unsigned sr, unsigned bw) {
192  sample_rate = sr;
193  frequency = fc;
194  bandwidth = bw;
195  antenna = ant;
196  if (g > 1) { g = 1; }
197  if (g < 0) { g = 0; }
198  gain = g;
199  spdlog::info("RESTful API requesting new parameters: fc {}, bw {}, rate {}, gain {}, antenna {}",
200  frequency, bandwidth, sample_rate, gain, antenna);
201 
202  restart = true;
203 }
204 
212 auto main(int argc, char **argv) -> int {
213  struct arguments arguments;
214  /* Default values */
215  arguments.config_file = "/etc/rp.conf";
216  arguments.sample_file = nullptr;
217  arguments.write_sample_file = nullptr;
218  argp_parse(&argp, argc, argv, 0, nullptr, &arguments);
219 
220  // Read and parse the configuration file
221  try {
222  cfg.readFile(arguments.config_file);
223  } catch(const FileIOException &fioex) {
224  spdlog::error("I/O error while reading config file at {}. Exiting.", arguments.config_file);
225  exit(1);
226  } catch(const ParseException &pex) {
227  spdlog::error("Config parse error at {}:{} - {}. Exiting.",
228  pex.getFile(), pex.getLine(), pex.getError());
229  exit(1);
230  }
231 
232  // Set up logging
233  std::string ident = "rp";
234  auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID | LOG_PERROR);
235 
236  spdlog::set_level(
237  static_cast<spdlog::level::level_enum>(arguments.log_level));
238  spdlog::set_pattern("[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
239 
240  spdlog::set_default_logger(syslog_logger);
241  spdlog::info("OBECA rp v{}.{}.{} starting up", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
242 
243 
244  // Init and tune the SDR
245  spdlog::info("Initialising LimeSDR");
246  LimeSdrReader lime(cfg);
247 
249  spdlog::error("Failed to initialize I/Q data source.");
250  exit(1);
251  }
252 
253  cfg.lookupValue("sdr.search_sample_rate_hz", sample_rate);
254  search_sample_rate = sample_rate;
255  cfg.lookupValue("sdr.center_frequency_hz", frequency);
256  cfg.lookupValue("sdr.normalized_gain", gain);
257  cfg.lookupValue("sdr.antenna", antenna);
258 
259  if (!lime.tune(frequency, sample_rate, bandwidth, gain, antenna)) {
260  spdlog::error("Failed to set initial center frequency. Exiting.");
261  exit(1);
262  }
263 
264  srslte_verbose = arguments.log_level == 1 ? 2 : 0;
265  srslte_use_standard_symbol_size(true);
266 
267  // Create a thread pool for the frame processors
268  unsigned thread_cnt = 4;
269  cfg.lookupValue("phy.threads", thread_cnt);
270  int phy_prio = 10;
271  cfg.lookupValue("phy.thread_priority_rt", phy_prio);
272  thread_pool pool{ thread_cnt + 1, phy_prio };
273 
274  // Elevate execution to real time scheduling
275  struct sched_param thread_param = {};
276  thread_param.sched_priority = 20;
277  cfg.lookupValue("phy.main_thread_priority_rt", thread_param.sched_priority);
278 
279  spdlog::info("Raising main thread to realtime scheduling priority {}", thread_param.sched_priority);
280 
281  int error = pthread_setschedparam(pthread_self(), SCHED_RR, &thread_param);
282  if (error != 0) {
283  spdlog::error("Cannot set main thread priority to realtime: {}. Thread will run at default priority.", strerror(error));
284  }
285 
286  bool enable_measurement_file = false;
287  cfg.lookupValue("measurement_file.enabled", enable_measurement_file);
288  MeasurementFileWriter measurement_file(cfg);
289 
290  // Create the layer components: Phy, RLC, RRC and GW
291  Phy phy(
292  cfg,
293  std::bind(&LimeSdrReader::getSamples, &lime, _1, _2, _3), // NOLINT
294  arguments.file_bw * 5,
296 
297  phy.init();
298 
299  srslte::pdcp pdcp(nullptr, "PDCP");
300  srslte::rlc rlc("RLC");
301  srslte::timer_handler timers;
302 
303  Rrc rrc(cfg, phy, rlc);
304  Gw gw(cfg, phy);
305  gw.init();
306 
307  rlc.init(&pdcp, &rrc, &timers, 0 /* RB_ID_SRB0 */);
308  pdcp.init(&rlc, &rrc, &gw);
309 
310  auto srs_level = srslte::LOG_LEVEL_WARNING;
311  switch (arguments.srs_log_level) {
312  case 0: srs_level = srslte::LOG_LEVEL_DEBUG; break;
313  case 1: srs_level = srslte::LOG_LEVEL_INFO; break;
314  case 2: srs_level = srslte::LOG_LEVEL_WARNING; break;
315  case 3: srs_level = srslte::LOG_LEVEL_ERROR; break;
316  case 4: srs_level = srslte::LOG_LEVEL_NONE; break;
317  }
318 
319  // Configure srsLTE logging
320  srslte::log_ref rlc_log = srslte::logmap::get("RLC");
321  rlc_log->set_level(srs_level);
322  rlc_log->set_hex_limit(128);
323 
324  srslte::log_ref mac_log = srslte::logmap::get("MAC");
325  mac_log->set_level(srs_level);
326  mac_log->set_hex_limit(128);
327 
328  state_t state = searching;
329 
330  // Create the RESTful API handler
331  std::string uri = "http://0.0.0.0:3000/rp-api/";
332  cfg.lookupValue("restful_api.uri", uri);
333  spdlog::info("Starting RESTful API handler at {}", uri);
334  RestHandler rest_handler(cfg, uri, state, lime, phy, set_params);
335 
336  // Initialize one CAS and thered_cnt MBSFN frame processors
337  CasFrameProcessor cas_processor(cfg, phy, rlc, rest_handler);
338  if (!cas_processor.init()) {
339  spdlog::error("Failed to create CAS processor. Exiting.");
340  exit(1);
341  }
342 
343  std::vector<MbsfnFrameProcessor*> mbsfn_processors;
344  for (int i = 0; i < thread_cnt; i++) {
345  auto p = new MbsfnFrameProcessor(cfg, rlc, phy, mac_log, rest_handler);
346  if (!p->init()) {
347  spdlog::error("Failed to create MBSFN processor. Exiting.");
348  exit(1);
349  }
350  mbsfn_processors.push_back(p);
351  }
352 
353  // Start receiving sample data
354  lime.start();
355 
356  uint32_t tti = 0;
357 
358  uint32_t measurement_interval = 5;
359  cfg.lookupValue("measurement_file.interval_secs", measurement_interval);
360  measurement_interval *= 1000;
361  uint32_t tick = 0;
362 
363  // Initial state: searching a cell
364  state = searching;
365 
366  // Start the main processing loop
367  for (;;) {
368  if (state == searching) {
369  if (restart) {
370  lime.stop();
371  sample_rate = search_sample_rate; // sample rate for searching
372  lime.tune(frequency, sample_rate, bandwidth, gain, antenna);
373  lime.start();
374  }
375  // In searching state, clear the receive buffer and try to find a cell at the configured frequency and synchronize with it
376  restart = false;
377  lime.clear_buffer();
378  bool cell_found = phy.cell_search();
379  if (cell_found) {
380  // A cell has been found. We now know the required number of PRB = bandwidth of the carrier. Set the approproiate
381  // sample rate...
382  cas_nof_prb = mbsfn_nof_prb = phy.nr_prb();
383  unsigned new_srate = srslte_sampling_freq_hz(cas_nof_prb);
384  spdlog::info("Setting sample rate {} Mhz for {} PRB / {} Mhz channel width", new_srate/1000000.0, phy.nr_prb(),
385  phy.nr_prb() * 0.2);
386  lime.stop();
387 
388  bandwidth = (cas_nof_prb * 200000) * 1.2;
389  lime.tune(frequency, new_srate, bandwidth, gain, antenna);
390  lime.start();
391  spdlog::debug("Synchronizing subframe");
392  // ... and move to syncing state.
393  state = syncing;
394  } else {
395  sleep(1);
396  }
397  } else if (state == syncing) {
398  // In syncing state, we already know the cell we want to camp on, and the SDR is tuned to the required
399  // sample rate for its number of PRB / bandwidth. We now synchronize PSS/SSS and receive the MIB once again
400  // at this sample rate.
401  unsigned max_frames = 200;
402  bool sfn_sync = false;
403  while (!sfn_sync && max_frames-- > 0) {
404  sfn_sync = phy.synchronize_subframe();
405  }
406 
407  if (max_frames == 0 && !sfn_sync) {
408  // Failed. Back to square one: search state.
409  spdlog::warn("Synchronization failed. Going back to search state.");
410  state = searching;
411  sleep(1);
412  }
413 
414  if (sfn_sync) {
415  // We're locked on to the cell, and have succesfully received the MIB at the target sample rate.
416  spdlog::info("Decoded MIB at target sample rate, TTI is {}. Subframe synchronized.", phy.tti());
417 
418  // Set the cell parameters in the CAS and MBSFN processors
419  cas_processor.set_cell(phy.cell());
420 
421  for (int i = 0; i < thread_cnt; i++) {
422  mbsfn_processors[i]->unlock();
423  }
424 
425  // Get the initial TTI / subframe ID (= system frame number * 10 + subframe number)
426  tti = phy.tti();
427  // Reset the RRC
428  rrc.reset();
429 
430  // Ready to receive actual data. Go to processing state.
431  state = processing;
432  }
433  } else { // processing
434  int mb_idx = 0;
435  while (state == processing) {
436  tti = (tti + 1) % 10240; // Clamp the TTI
437  if (tti%40 == 0) {
438  // This is subframe 0 in a radio frame divisible by 4, and hence a CAS frame.
439  // Get the samples from the SDR interface, hand them to a CAS processor, and start it
440  // on a thread from the pool.
441  if (!restart && phy.get_next_frame(cas_processor.rx_buffer(), cas_processor.rx_buffer_size())) {
442  spdlog::debug("sending tti {} to regular processor", tti);
443  pool.push([ObjectPtr = &cas_processor, tti] {
444  ObjectPtr->process(tti);
445  });
446 
447  // Set constellation diagram data and rx params for CAS in the REST API handler
448  rest_handler._ce_values = std::move(cas_processor.ce_values());
449  rest_handler._pdsch.SetData(cas_processor.pdsch_data());
450  rest_handler.add_cinr_value(cas_processor.cinr_db());
451 
452  if (phy.nof_mbsfn_prb() != mbsfn_nof_prb)
453  {
454  mbsfn_nof_prb = phy.nof_mbsfn_prb();
455  // Adjust the sample rate to fit the wider MBSFN bandwidth
456  unsigned new_srate = srslte_sampling_freq_hz(mbsfn_nof_prb);
457  spdlog::info("Setting sample rate {} Mhz for MBSFN with {} PRB / {} Mhz channel width", new_srate/1000000.0, mbsfn_nof_prb,
458  mbsfn_nof_prb * 0.2);
459  lime.stop();
460 
461  bandwidth = (mbsfn_nof_prb * 200000) * 1.2;
462  lime.tune(frequency, new_srate, bandwidth, gain, antenna);
463  lime.start();
464  spdlog::debug("Synchronizing subframe after PRB extension");
465  // ... and move to syncing state.
466  phy.set_cell();
467  cas_processor.set_cell(phy.cell());
468  state = syncing;
469  }
470  } else {
471  // Failed to receive data, or sync lost. Go back to searching state.
472  lime.stop();
473  sample_rate = search_sample_rate; // sample rate for searching
474  lime.tune(frequency, sample_rate, bandwidth, gain, antenna);
475  lime.start();
476  rrc.reset();
477  phy.reset();
478 
479  sleep(1);
480  state = searching;
481  }
482  } else {
483  // All other frames in FeMBMS dedicated mode are MBSFN frames.
484  spdlog::debug("sending tti {} to mbsfn proc {}", tti, mb_idx);
485 
486  // Get the samples from the SDR interface, hand them to an MNSFN processor, and start it
487  // on a thread from the pool. Getting the buffer pointer from the pool also locks this processor.
488  if (!restart && phy.get_next_frame(mbsfn_processors[mb_idx]->get_rx_buffer_and_lock(), mbsfn_processors[mb_idx]->rx_buffer_size())) {
489  if (phy.mcch_configured()) {
490  // If data frm SIB1/SIB13 has been received in CAS, configure the processors accordingly
491  if (!mbsfn_processors[mb_idx]->mbsfn_configured()) {
492  srslte_scs_t scs;
493  switch (phy.mbsfn_subcarrier_spacing()) {
494  case Phy::SubcarrierSpacing::df_15kHz: scs = SRSLTE_SCS_15KHZ; break;
495  case Phy::SubcarrierSpacing::df_7kHz5: scs = SRSLTE_SCS_7KHZ5; break;
496  case Phy::SubcarrierSpacing::df_1kHz25: scs = SRSLTE_SCS_1KHZ25; break;
497  }
498  auto cell = phy.cell();
499  cell.nof_prb = cell.mbsfn_prb;
500  mbsfn_processors[mb_idx]->set_cell(cell);
501  mbsfn_processors[mb_idx]->configure_mbsfn(phy.mbsfn_area_id(), scs);
502  }
503  pool.push([ObjectPtr = mbsfn_processors[mb_idx], tti] {
504  ObjectPtr->process(tti);
505  });
506  } else {
507  // Nothing to do yet, we lack the data from SIB1/SIB13
508  // Discard the samples and unlock the processor.
509  mbsfn_processors[mb_idx]->unlock();
510  }
511  } else {
512  // Failed to receive data, or sync lost. Go back to searching state.
513  spdlog::warn("Synchronization lost while processing. Going back to searching state.");
514  lime.stop();
515  sample_rate = search_sample_rate; // sample rate for searching
516  lime.tune(frequency, sample_rate, bandwidth, gain, antenna);
517  lime.start();
518 
519  state = searching;
520  sleep(1);
521  rrc.reset();
522  phy.reset();
523  }
524  mb_idx = static_cast<int>((mb_idx + 1) % thread_cnt);
525  }
526 
527  tick++;
528  if (tick%measurement_interval == 0) {
529  // It's time to output rx info to the measurement file and to syslog.
530  // Collect the relevant info and write it out.
531  std::vector<std::string> cols;
532 
533  spdlog::info("CINR {:.2f} dB", rest_handler.cinr_db() );
534  cols.push_back(std::to_string(rest_handler.cinr_db()));
535 
536  spdlog::info("PDSCH: MCS {}, BLER {}, BER {}",
537  rest_handler._pdsch.mcs,
538  ((rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0)),
539  rest_handler._pdsch.ber);
540  cols.push_back(std::to_string(rest_handler._pdsch.mcs));
541  cols.push_back(std::to_string(((rest_handler._pdsch.errors * 1.0) / (rest_handler._pdsch.total * 1.0))));
542  cols.push_back(std::to_string(rest_handler._pdsch.ber));
543 
544  spdlog::info("MCCH: MCS {}, BLER {}, BER {}",
545  rest_handler._mcch.mcs,
546  ((rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0)),
547  rest_handler._mcch.ber);
548 
549  cols.push_back(std::to_string(rest_handler._mcch.mcs));
550  cols.push_back(std::to_string(((rest_handler._mcch.errors * 1.0) / (rest_handler._mcch.total * 1.0))));
551  cols.push_back(std::to_string(rest_handler._mcch.ber));
552 
553  auto mch_info = phy.mch_info();
554  int mch_idx = 0;
555  std::for_each(std::begin(mch_info), std::end(mch_info), [&cols, &mch_idx, &rest_handler](Phy::mch_info_t const& mch) {
556  spdlog::info("MCH {}: MCS {}, BLER {}, BER {}",
557  mch_idx,
558  mch.mcs,
559  (rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0),
560  rest_handler._mch[mch_idx].ber);
561  cols.push_back(std::to_string(mch_idx));
562  cols.push_back(std::to_string(mch.mcs));
563  cols.push_back(std::to_string((rest_handler._mch[mch_idx].errors * 1.0) / (rest_handler._mch[mch_idx].total * 1.0)));
564  cols.push_back(std::to_string(rest_handler._mch[mch_idx].ber));
565 
566  int mtch_idx = 0;
567  std::for_each(std::begin(mch.mtchs), std::end(mch.mtchs), [&mtch_idx](Phy::mtch_info_t const& mtch) {
568  spdlog::info(" MTCH {}: LCID {}, TMGI 0x{}, {}",
569  mtch_idx,
570  mtch.lcid,
571  mtch.tmgi,
572  mtch.dest);
573  mtch_idx++;
574  });
575  mch_idx++;
576  });
577  spdlog::info("-----");
578  if (enable_measurement_file) {
579  measurement_file.WriteLogValues(cols);
580  }
581  }
582  }
583  }
584  }
585 
586  // Main loop ended by signal. Free the MBSFN processors, and bail.
587  for (int i = 0; i < thread_cnt; i++) {
588  delete( mbsfn_processors[i] );
589  }
590 exit:
591  return 0;
592 }
Rrc
Simple RRC component between PHY and RLC.
Definition: Rrc.h:34
arguments::srs_log_level
unsigned srs_log_level
srsLTE log level
Definition: main.cpp:101
MeasurementFileWriter
Writes measurement data / current reception parameters to a file.
Definition: MeasurementFileWriter.h:35
LimeSdrReader::tune
bool tune(uint32_t frequency, uint32_t sample_rate, uint32_t bandwidth, double gain, const std::string &antenna)
Tune the SDR to the desired frequency, and set gain, filter and antenna parameters.
Definition: LimeSdrReader.cpp:129
arguments::log_level
unsigned log_level
log level
Definition: main.cpp:100
LimeSdrReader::getSamples
int getSamples(cf_t *data, uint32_t nsamples, srslte_timestamp_t *rx_time)
Store nsamples count samples into the buffer at data.
Definition: LimeSdrReader.cpp:306
RestHandler::_pdsch
ChannelInfo _pdsch
RX info for PDSCH.
Definition: RestHandler.h:101
Phy::nr_prb
unsigned nr_prb()
Get the current number of PRB.
Definition: Phy.h:99
CasFrameProcessor::init
bool init()
Initialize signal- and softbuffers, init all underlying components.
Definition: CasFrameProcessor.cpp:24
Gw
Network gateway component.
Definition: Gw.h:34
arguments
Holds all options passed on the command line.
Definition: main.cpp:98
CasFrameProcessor
Frame processor for CAS subframes.
Definition: CasFrameProcessor.h:38
Phy
The PHY component.
Definition: Phy.h:43
main
auto main(int argc, char **argv) -> int
Main entry point for the program.
Definition: main.cpp:212
Phy::reset
void reset()
Clear configuration values.
Definition: Phy.h:129
Phy::nof_mbsfn_prb
uint8_t nof_mbsfn_prb()
Get number of PRB in MBSFN/PMCH.
Definition: Phy.h:154
Phy::mbsfn_area_id
uint8_t mbsfn_area_id()
Returns the current MBSFN area ID.
Definition: Phy.h:139
Phy::mtch_info_t
Definition: Phy.h:158
MbsfnFrameProcessor
Frame processor for MBSFN subframes.
Definition: MbsfnFrameProcessor.h:39
arguments::sample_file
const char * sample_file
file path of the sample file.
Definition: main.cpp:103
Phy::mcch_configured
bool mcch_configured()
Return true if MCCH has been configured.
Definition: Phy.h:134
LimeSdrReader::init
bool init(uint8_t device_index, const char *sample_file, const char *write_sample_file)
Initializes the SDR interface and creates a ring buffer according to the params from Cfg.
Definition: LimeSdrReader.cpp:42
set_params
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:191
arguments::override_nof_prb
int8_t override_nof_prb
ovride PRB number
Definition: main.cpp:102
Phy::get_next_frame
bool get_next_frame(cf_t **buffer, uint32_t size)
Get the sample data for the next subframe.
Definition: Phy.cpp:190
Phy::init
bool init()
Initialize the underlying components.
Definition: Phy.cpp:162
LimeSdrReader::start
void start()
Start reading samples from the SDR.
Definition: LimeSdrReader.cpp:238
arguments::write_sample_file
const char * write_sample_file
file path of the created sample file.
Definition: main.cpp:106
CasFrameProcessor::pdsch_data
std::vector< uint8_t > pdsch_data()
Get the constellation diagram data (I/Q data of the subcarriers after CE)
Definition: CasFrameProcessor.cpp:168
CasFrameProcessor::cinr_db
float cinr_db()
Get the CINR estimate (in dB)
Definition: CasFrameProcessor.h:104
CasFrameProcessor::set_cell
void set_cell(srslte_cell_t cell)
Set the parameters for the cell (Nof PRB, etc).
Definition: CasFrameProcessor.cpp:81
RestHandler::_mch
std::map< uint32_t, ChannelInfo > _mch
RX info for MCHs.
Definition: RestHandler.h:111
RestHandler::_ce_values
std::vector< uint8_t > _ce_values
Time domain subcarrier CE values.
Definition: RestHandler.h:96
LimeSdrReader::clear_buffer
void clear_buffer()
Clear all samples from the rx buffers.
Definition: LimeSdrReader.cpp:120
Phy::synchronize_subframe
bool synchronize_subframe()
Synchronizes PSS/SSS and tries to deocode the MIB.
Definition: Phy.cpp:55
Phy::cell
srslte_cell_t cell()
Get the current cell (with params adjusted for MBSFN)
Definition: Phy.h:92
LimeSdrReader::stop
void stop()
Stop reading samples from the SDR.
Definition: LimeSdrReader.cpp:256
CasFrameProcessor::rx_buffer_size
uint32_t rx_buffer_size()
Size of the signal buffer.
Definition: CasFrameProcessor.h:88
RestHandler
The RESTful API handler.
Definition: RestHandler.h:47
Phy::cell_search
bool cell_search()
Search for a cell.
Definition: Phy.cpp:82
CasFrameProcessor::rx_buffer
cf_t ** rx_buffer()
Get a handle of the signal buffer to store samples for processing in.
Definition: CasFrameProcessor.h:83
RestHandler::_mcch
ChannelInfo _mcch
RX info for MCCH.
Definition: RestHandler.h:106
MeasurementFileWriter::WriteLogValues
void WriteLogValues(const std::vector< std::string > &values)
Write a line containing the passed values.
Definition: MeasurementFileWriter.cpp:100
RestHandler::cinr_db
float cinr_db()
Current CINR value.
Definition: RestHandler.h:116
CasFrameProcessor::ce_values
std::vector< uint8_t > ce_values()
Get the CE values (time domain) for displaying the spectrum of the received signal.
Definition: CasFrameProcessor.cpp:158
Phy::tti
uint32_t tti()
Get the current subframe TTI.
Definition: Phy.h:104
arguments::config_file
const char * config_file
file path of the config file.
Definition: main.cpp:99
Phy::mch_info_t
Definition: Phy.h:163
LimeSdrReader
Interface to LimeSDR via LimeSuite.
Definition: LimeSdrReader.h:36
arguments::file_bw
uint8_t file_bw
bandwidth of the sample file
Definition: main.cpp:104
Gw::init
void init()
Creates the TUN interface according to params from Cfg.
Definition: Gw.cpp:99