free5GRAN  V1.0
main.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Telecom Paris
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16 
17 #include <uhd/utils/thread.hpp>
18 #include <uhd/utils/safe_main.hpp>
19 #include <uhd/usrp/multi_usrp.hpp>
20 #include <uhd/exception.hpp>
21 #include <uhd/types/tune_request.hpp>
22 #include <boost/program_options.hpp>
23 #include <boost/format.hpp>
24 #include <boost/thread.hpp>
25 #include <iostream>
26 #include <fstream>
27 #include <chrono>
28 #include <libconfig.h++>
29 #include <boost/log/core.hpp>
30 #include <boost/log/trivial.hpp>
31 #include <boost/log/expressions.hpp>
32 #include <boost/log/utility/setup/file.hpp>
33 #include <boost/log/utility/setup/common_attributes.hpp>
34 
35 #include "rf/rf.h"
36 #include "../lib/variables/common_variables/common_variables.h"
37 #include "phy/phy.h"
38 #include "../lib/phy/libphy/libphy.h"
39 #include "../lib/asn1c/nr_rrc/SIB1.h"
40 #include "../lib/variables/common_variables/common_variables.h"
41 
42 using namespace std;
43 
44 /*
45  * Define structure to store found cells
46  */
47 typedef struct found_cell_ {
50  double gain;
51  int gscn, scs;
52  bool dci_found;
53 
54 } found_cell;
55 
56 void search_cell_with_defined_params(double frequency, double ssb_period, const string &rf_address, free5GRAN::band band, int input_gain);
57 void scan_bands(vector<free5GRAN::band> BANDS, double ssb_period, const string &rf_address, int input_gain);
58 void init_logging(const string &level);
59 
60 
61 int main(int argc, char *argv[]) {
62 
63  //ofstream out("out.txt");
64  //cout.rdbuf(out.rdbuf());
65 
66 
67 
68  libconfig::Config cfg;
69 
70  try
71  {
72  cfg.readFile(argv[1]);
73  cout << "Using configuration file $PWD/" << argv[1] << endl;
74  }
75  catch(const libconfig::FileIOException &fioex)
76  {
77  try
78  {
79  string path = "/root/.config/free5GRAN/config/free5GRAN.cfg";
80  cfg.readFile(path.c_str());
81  cout << "Using configuration file " << path << endl;
82  }
83  catch(const libconfig::FileIOException &fioex)
84  {
85  cerr << "Please provide a config file!" << endl;
86  return(EXIT_FAILURE);
87  }
88  }
89  catch(const libconfig::ParseException &pex)
90  {
91  cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
92  << " - " << pex.getError() << endl;
93  return(EXIT_FAILURE);
94  }
95 
96  try
97  {
98  string level;
99  if (!cfg.lookupValue("logging", level)){
100  level = "info";
101  }
102  init_logging(level);
103  BOOST_LOG_TRIVIAL(info) << "Initializing free5GRAN";
104  string func = cfg.lookup("function");
105  string rf_address = cfg.lookup("rf_address");
106  int gain = cfg.lookup("gain");
107  const libconfig::Setting& root = cfg.getRoot();
108  if (func == "CELL_SEARCH"){
109  cout << "## CELL SEARCH ##" << endl;
110  BOOST_LOG_TRIVIAL(info) << "CELL SEARCH";
111  const libconfig::Setting& cell_info = root["cell_info"];
112  double ssb_period;
113  int band;
114  free5GRAN::band band_obj;
115  if (!root.lookupValue("ssb_period", ssb_period)){
116  // Default ssb period to 20 ms
117  ssb_period = 0.02;
118  }if (cell_info.lookupValue("band", band) ){
119  bool found_band = false;
120  for (int j = 0; j < free5GRAN::NUM_SUPPORTED_BANDS; j ++){
121  if (free5GRAN::AVAILABLE_BANDS[j].number == band){
122  band_obj = free5GRAN::AVAILABLE_BANDS[j];
123  found_band = true;
124  BOOST_LOG_TRIVIAL(trace) << "Band n" + to_string(band);
125  break;
126  }
127  }
128  if (found_band) {
129  double frequency;
130  int gscn;
131  if (cell_info.lookupValue("ssb_frequency", frequency) || cell_info.lookupValue("gscn", gscn)){
132  if (!cell_info.lookupValue("ssb_frequency", frequency)){
134  }
135  search_cell_with_defined_params(frequency, ssb_period, rf_address,band_obj, gain);
136  }
137  else {
138  cerr << "Missing parameters (frequency or GSCN) in config file" << endl;
139  }
140  }else {
141  cout << "BAND not supported" << endl;
142  }
143  }
144  else {
145  cerr << "Missing parameters (band) in config file" << endl;
146  }
147  }else if (func == "BAND_SCAN"){
148  BOOST_LOG_TRIVIAL(info) << "BAND SCANNING";
149  cout << "## BAND SCAN ##" << endl;
150  const libconfig::Setting& bands = root["bands"];
151  int count = bands.getLength();
152  vector<free5GRAN::band> band_array;
153  BOOST_LOG_TRIVIAL(trace) << "Adding bands to scan: ";
154  for (int i = 0; i < count; i ++){
155  int band_id = bands[i];
156  for (int j = 0; j < free5GRAN::NUM_SUPPORTED_BANDS; j ++){
157  if (free5GRAN::AVAILABLE_BANDS[j].number == band_id){
158  band_array.push_back(free5GRAN::AVAILABLE_BANDS[j]);
159  BOOST_LOG_TRIVIAL(trace) << "Band n" + to_string(band_id);
160  break;
161  }
162  }
163  }
164  double ssb_period;
165  if (!root.lookupValue("ssb_period", ssb_period)){
166  // Default ssb period to 20 ms
167  ssb_period = 0.02;
168  }
169  scan_bands(band_array, ssb_period, rf_address, gain);
170  }
171  }
172  catch(const libconfig::SettingNotFoundException &nfex)
173  {
174  cerr << "Missing function, RF device address of gain in config file" << endl;
175  }
176 
177  return EXIT_SUCCESS;
178 }
179 
180 
181 void scan_bands(vector<free5GRAN::band> BANDS, double ssb_period, const string &rf_address, int input_gain){
182  /*
183  * USRP parameters
184  */
185  string device_args("serial="+rf_address);
186  string subdev("A:A");
187  string ant("TX/RX");
188  string ref("internal");
189  /*
190  * Cell default parameters
191  */
192  double freq(1000e6);
193  double rate(3.84e6);
194  double gain(input_gain);
195  double bw(3.84e6);
196 
197  free5GRAN::band current_band;
198 
199 
200  // Search cell with 15kHz SCS
201  rf rf_device(rate, freq, gain, bw, subdev, ant, ref, device_args);
202  vector<found_cell> found_cells;
203  cout << "\n";
204  auto start = chrono::high_resolution_clock::now();
205  float received_power;
206  /*
207  * Loop over each supported band
208  */
209  for (int i = 0; i < BANDS.size() ; i ++){
210  current_band = BANDS[i];
211  BOOST_LOG_TRIVIAL(info) << "###########################################";
212  BOOST_LOG_TRIVIAL(info) << "Scanning band n"+ to_string(current_band.number);
213  /*
214  * Search a cell by scanning different possible GSCN
215  */
216  for (int gscn = current_band.min_gscn; gscn <= current_band.max_gscn; gscn ++){
217  /*
218  * Reconfigure RF device and instanciate a phy object
219  */
221  BOOST_LOG_TRIVIAL(info) << "Scanning gscn= "+ to_string(gscn) + " and freq= " + to_string(freq/1e6) + " MHz";
222 
223  free5GRAN::bandwidth_info band_info;
224  if (freq < 3000e6){
225  band_info = free5GRAN::BANDWIDTH_15_KHZ;
226  }else {
227  band_info = free5GRAN::BANDWIDTH_30_KHZ;
228  }
229  BOOST_LOG_TRIVIAL(trace) << "Bandwidth informations are: ";
230  BOOST_LOG_TRIVIAL(trace) << "SCS: " + to_string(band_info.scs);
231 
232  int fft_size_pss = 128;
233  rf_device.setCenterFrequency(freq);
234  rf_device.setSampleRate(fft_size_pss * band_info.scs);
235  rf_device.setGain(100);
236  phy phy_layer(&rf_device, ssb_period, fft_size_pss, band_info.scs, current_band);
237 
238 
239  cout << "\r## Searching in band n" + to_string(current_band.number) + " - " + to_string((((float) gscn - (float) current_band.min_gscn)/((float) current_band.max_gscn - (float) current_band.min_gscn)) * 100.0) + "% (found " + to_string(found_cells.size()) + " cells)";
240 
241  /*
242  * If a PSS is correlate with a good peak value
243  */
244  if (phy_layer.cell_synchronization(received_power)==0){
245  /*
246  * Power down-ramping to avoid saturation
247  */
248  BOOST_LOG_TRIVIAL(trace) << "Received power: " + to_string(received_power) + " dB (Gain= "+ to_string(rf_device.getGain()) +" dB)";
249  while (received_power > -2 && rf_device.getGain() > 0){
250  rf_device.setGain(rf_device.getGain()-10);
251  phy_layer.cell_synchronization(received_power);
252  BOOST_LOG_TRIVIAL(trace) << "Received power: " + to_string(received_power) + " dB (Gain= "+ to_string(rf_device.getGain()) +" dB)";
253  }
254  BOOST_LOG_TRIVIAL(trace) << "Final received power: " + to_string(received_power) + " dB (Final gain= "+ to_string(rf_device.getGain()) +" dB)";
255  /*
256  * If the re-computed PCI is equal to the initially computed one
257  */
258  rf_device.setSampleRate(30.72e6);
259  int new_fft_size;
260  new_fft_size = (int) (30.72e6/band_info.scs);
261  phy_layer.reconfigure(new_fft_size);
262 
263  if(phy_layer.extract_pbch() == 0){
264  //phy_layer.print_cell_info();
265  bool dci_found;
266  phy_layer.search_pdcch(dci_found);
267  if (dci_found){
268  phy_layer.extract_pdsch();
269  }
270  found_cell new_cell;
271  new_cell.band_obj = current_band;
272  new_cell.scs = current_band.scs;
273  new_cell.gscn = gscn;
274  new_cell.phy_obj = phy_layer;
275  new_cell.gain = rf_device.getGain();
276  new_cell.dci_found = dci_found;
277  found_cells.push_back(new_cell);
278  }
279  }
280  }
281  }
282  for (int i = 0; i < found_cells.size(); i ++){
283  cout << "\n";
284  cout << "#######################################################################" << endl;
285  cout << "########################## CELL " + to_string(i) + " ##########################" << endl;
286  cout << "#######################################################################" << endl;
287  cout << "# GSCN: " + to_string(found_cells[i].gscn) + " / Frequency: " + to_string(free5GRAN::phy::signal_processing::compute_freq_from_gscn(found_cells[i].gscn)/1e6) + " MHz (band n" + to_string(found_cells[i].band_obj.number) + ")" << endl;
288  cout << "# Gain: " + to_string(found_cells[i].gain) + " dB"<< endl;
289  found_cells[i].phy_obj.print_cell_info();
290  if (found_cells[i].dci_found || found_cells[i].phy_obj.getSIB1RV() == 1 || found_cells[i].phy_obj.getSIB1RV() == 2){
291  found_cells[i].phy_obj.print_dci_info();
292  try {
293  found_cells[i].phy_obj.print_sib1();
294  } catch (const std::exception& e) { cout << "NO SIB1" << endl; }
295  }else {
296  cout << "###### DCI" << endl;
297  cout << "# DCI not found, not CRC validated, or unsupported RV";
298  cout << "\n";
299  }
300  cout << "#######################################################################" << endl;
301 
302  }
303  auto stop = chrono::high_resolution_clock::now();
304  auto duration = chrono::duration_cast<chrono::microseconds>(stop - start);
305  cout << "Executed in "+ to_string(duration.count()/1e6) + " seconds" << endl;
306 }
307 
308 
309 
310 void search_cell_with_defined_params(double frequency, double ssb_period, const string &rf_address, free5GRAN::band band, int input_gain){
311  /*
312  * USRP parameters
313  */
314  string device_args("serial="+rf_address);
315  string subdev("A:A");
316  string ant("TX/RX");
317  string ref("internal");
318  /*
319  * Cell parameters
320  */
321  double gain(input_gain);
322  free5GRAN::bandwidth_info band_info;
323  if (frequency < 3000e6){
324  band_info = free5GRAN::BANDWIDTH_15_KHZ;
325  }else {
326  band_info = free5GRAN::BANDWIDTH_30_KHZ;
327  }
328  BOOST_LOG_TRIVIAL(trace) << "Bandwidth informations are: ";
329  BOOST_LOG_TRIVIAL(trace) << "SCS: " + to_string(band_info.scs);
330  /*
331  * Instanciate a rf layer instance to provide exchanges with USRP device
332  */
333  int fft_size_pss = 128;
334  rf rf_device(fft_size_pss * band_info.scs, frequency, gain, fft_size_pss * band_info.scs, subdev, ant, ref, device_args);
335 
336  //FIX BAND SELECTION
337 
338  phy phy_layer(&rf_device, ssb_period, fft_size_pss, band_info.scs, band);
339 
340 
341  cout << "\n";
342  cout << "########################## Searching cell ##########################" << endl;
343  cout << "\n";
344  cout << "###### RADIO" << endl;
345  cout << "# Frequency: " + to_string(frequency/1e6) + " MHz" << endl;
346  cout << "# SCS: " + to_string(band_info.scs/1e3) + " kHz" << endl;
347  cout << "\n";
348 
349  BOOST_LOG_TRIVIAL(info) << "Searching cell with frequency = " + to_string(frequency/1e6) + " MHz and SCS = " + to_string(band_info.scs/1e3) + " kHz";
350 
351  float received_power;
352  if (phy_layer.cell_synchronization(received_power) == 0){
353  /*
354  * Power down-ramping to avoid saturation
355  */
356  cout << "###### Power ramping" << endl;
357  cout << "Received power: "+ to_string(received_power) + " dB" << endl;
358  BOOST_LOG_TRIVIAL(trace) << "Received power: " + to_string(received_power) + " dB (Gain= "+ to_string(rf_device.getGain()) +" dB)";
359 
360  while (received_power > -2 && rf_device.getGain() > 0){
361  rf_device.setGain(rf_device.getGain()-10);
362  phy_layer.cell_synchronization(received_power);
363  cout << "New gain: "+ to_string(rf_device.getGain()) + " dB" << endl;
364  cout << "Received power: "+ to_string(received_power) + " dB" << endl;
365  BOOST_LOG_TRIVIAL(trace) << "Received power: " + to_string(received_power) + " dB (Gain= "+ to_string(rf_device.getGain()) +" dB)";
366  }
367  cout << "\n";
368  BOOST_LOG_TRIVIAL(trace) << "Final received power: " + to_string(received_power) + " dB (Final gain= "+ to_string(rf_device.getGain()) +" dB)";
369  rf_device.setSampleRate(30.72e6);
370  int new_fft_size;
371  new_fft_size = (int) (30.72e6/band_info.scs);
372  phy_layer.reconfigure(new_fft_size);
373 
374  if(phy_layer.extract_pbch() == 0){
375  phy_layer.print_cell_info();
376  bool dci_found;
377  phy_layer.search_pdcch(dci_found);
378  phy_layer.print_dci_info();
379  if (dci_found){
380  phy_layer.extract_pdsch();
381  phy_layer.print_sib1();
382  }
383  cout << "####################################################################" << endl;
384  }else {
385  cout << "########################## Cell not confirmed ##########################" << endl;
386  cout << "####################################################################" << endl;
387  }
388  }else {
389  cout << "########################## Cell not found ##########################" << endl;
390  cout << "####################################################################" << endl;
391  }
392  cout << "####################################################################" << endl;
393 
394 }
395 
396 void init_logging(const string &level)
397 {
398  boost::log::register_simple_formatter_factory<boost::log::trivial::severity_level, char>("Severity");
399 
400  boost::log::add_file_log
401  (
402  boost::log::keywords::file_name = "/var/log/free5GRAN/free5GRAN.log",
403  boost::log::keywords::format = "[%TimeStamp%] [%ThreadID%] [%Severity%] %Message%"
404  );
405 
406  if (level == "trace"){
407  boost::log::core::get()->set_filter
408  (
409  boost::log::trivial::severity >= boost::log::trivial::trace
410  );
411  }else if (level == "debug"){
412  boost::log::core::get()->set_filter
413  (
414  boost::log::trivial::severity >= boost::log::trivial::debug
415  );
416  }else if (level == "info"){
417  boost::log::core::get()->set_filter
418  (
419  boost::log::trivial::severity >= boost::log::trivial::info
420  );
421  }else if (level == "warning"){
422  boost::log::core::get()->set_filter
423  (
424  boost::log::trivial::severity >= boost::log::trivial::warning
425  );
426  }else if (level == "error"){
427  boost::log::core::get()->set_filter
428  (
429  boost::log::trivial::severity >= boost::log::trivial::error
430  );
431  }else {
432  boost::log::core::get()->set_filter
433  (
434  boost::log::trivial::severity >= boost::log::trivial::fatal
435  );
436  }
437 
438  boost::log::add_common_attributes();
439 }
void setSampleRate(double rate)
Definition: rf.cpp:126
struct free5GRAN::band_ band
void search_pdcch(bool &validated)
Definition: phy.cpp:515
Definition: phy.h:27
void print_cell_info()
Definition: phy.cpp:476
void scan_bands(vector< free5GRAN::band > BANDS, double ssb_period, const string &rf_address, int input_gain)
Definition: main.cc:181
void extract_pdsch()
Definition: phy.cpp:894
int scs
Definition: main.cc:51
int extract_pbch()
Definition: phy.cpp:188
double gain
Definition: main.cc:50
void setCenterFrequency(double freq)
Definition: rf.cpp:141
free5GRAN::band band_obj
Definition: main.cc:48
void search_cell_with_defined_params(double frequency, double ssb_period, const string &rf_address, free5GRAN::band band, int input_gain)
Definition: main.cc:310
void print_dci_info()
Definition: phy.cpp:841
void init_logging(const string &level)
Definition: main.cc:396
bandwidth_info BANDWIDTH_15_KHZ
double compute_freq_from_gscn(int gscn)
Definition: libphy.cpp:338
int main(int argc, char *argv[])
Definition: main.cc:61
struct found_cell_ found_cell
bandwidth_info BANDWIDTH_30_KHZ
int cell_synchronization(float &received_power)
Definition: phy.cpp:60
bool dci_found
Definition: main.cc:52
void print_sib1()
Definition: phy.cpp:1099
void reconfigure(int fft_size)
Definition: phy.cpp:511
void setGain(double gain)
Definition: rf.cpp:153
free5GRAN::band AVAILABLE_BANDS[7]
double getGain()
Definition: rf.cpp:163
int gscn
Definition: main.cc:51
phy phy_obj
Definition: main.cc:49
Definition: rf.h:29