diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c943e0f58..b9a33105f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -123,9 +123,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: install dependencies - run: | - python -m pip install --upgrade pip - pip install mako + run: sudo apt install python3-mako liborc-dev - name: configure run: cd build && cmake ../src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr - name: build diff --git a/CMakeLists.txt b/CMakeLists.txt index b7e627037..10092b46d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,13 +326,13 @@ set(GNSSSDR_PROTOBUF_MIN_VERSION "3.0.0") ################################################################################ set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.2") set(GNSSSDR_GLOG_LOCAL_VERSION "0.4.0") -set(GNSSSDR_ARMADILLO_LOCAL_VERSION "10.1.x") +set(GNSSSDR_ARMADILLO_LOCAL_VERSION "10.2.x") set(GNSSSDR_GTEST_LOCAL_VERSION "1.10.0") set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master") set(GNSSSDR_GPSTK_LOCAL_VERSION "8.0.0") set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.19") set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.11.4") -set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "3.15.0") +set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "3.15.2") set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.5.2") set(GNSSSDR_MATHJAX_EXTERNAL_VERSION "2.7.7") diff --git a/README.md b/README.md index 767f0b407..220912c66 100644 --- a/README.md +++ b/README.md @@ -292,9 +292,9 @@ $ sudo apt-get install libblas-dev liblapack-dev # For Debian/Ubuntu/Linux $ sudo yum install lapack-devel blas-devel # For Fedora/CentOS/RHEL $ sudo zypper install lapack-devel blas-devel # For OpenSUSE $ sudo pacman -S blas lapack # For Arch Linux -$ wget http://sourceforge.net/projects/arma/files/armadillo-10.1.2.tar.xz -$ tar xvfz armadillo-10.1.2.tar.xz -$ cd armadillo-10.1.2 +$ wget http://sourceforge.net/projects/arma/files/armadillo-10.2.1.tar.xz +$ tar xvfz armadillo-10.2.1.tar.xz +$ cd armadillo-10.2.1 $ cmake . $ make $ sudo make install diff --git a/conf/gnss-sdr_GPS_L1_FPGA.conf b/conf/gnss-sdr_GPS_L1_FPGA.conf index 52a2d883d..c18b357b8 100644 --- a/conf/gnss-sdr_GPS_L1_FPGA.conf +++ b/conf/gnss-sdr_GPS_L1_FPGA.conf @@ -10,77 +10,67 @@ [GNSS-SDR] ;######### GLOBAL OPTIONS ################## -;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [samples per second]. -GNSS-SDR.internal_fs_sps=4000000 - +GNSS-SDR.internal_fs_sps=12500000 +GNSS-SDR.enable_FPGA=true ;######### SIGNAL_SOURCE CONFIG ############ -SignalSource.implementation=Pass_Through -SignalSource.filename=/datalogger/signals/Agilent/New York/4msps.dat ; <- PUT YOUR FILE HERE -SignalSource.item_type=ishort -SignalSource.sampling_frequency=4000000 +SignalSource.implementation=Ad9361_Fpga_Signal_Source +SignalSource.sampling_frequency=12500000 SignalSource.freq=1575420000 -SignalSource.repeat=false -SignalSource.dump=false -SignalSource.dump_filename=../data/signal_source.dat -SignalSource.enable_throttle_control=false -SignalSource.enable_FPGA=true - +SignalSource.switch_position=2 +SignalSource.gain_mode_rx1=slow_attack ;######### SIGNAL_CONDITIONER CONFIG ############ SignalConditioner.implementation=Pass_Through -SignalConditioner.item_type=cshort SignalConditioner.enable_FPGA=true ;######### CHANNELS GLOBAL CONFIG ############ -Channels_1C.count=8 Channels.in_acquisition=1 -Channel.signal=1C -Channel.enable_FPGA=true +Channels_1C.count=12 - -;######### ACQUISITION GLOBAL CONFIG ############ +;######### GPS ACQUISITION CONFIG ############ Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition_Fpga -Acquisition_1C.dump=false -Acquisition_1C.dump_filename=./acq_dump.dat -Acquisition_1C.item_type=cshort -Acquisition_1C.coherent_integration_time_ms=1 -Acquisition_1C.select_queue_Fpga=0; -Acquisition_1C.threshold=0.005 -;Acquisition_1C.pfa=0.01 -Acquisition_1C.doppler_max=10000 -Acquisition_1C.doppler_step=500 +Acquisition_1C.threshold=2.0 +Acquisition_1C.doppler_max=50000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.make_two_steps=true +Acquisition_1C.second_nbins=3 +Acquisition_1C.doppler_step2=250 +Acquisition_1C.max_num_acqs=100 -;######### TRACKING GLOBAL CONFIG ############ +;######### TRACKING GPS CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking_Fpga -Tracking_1C.item_type=cshort -Tracking_1C.dump=false -Tracking_1C.dump_filename=../data/epl_tracking_ch_ -Tracking_1C.pll_bw_hz=45.0; +Tracking_1C.extend_correlation_symbols=20 +Tracking_1C.pll_bw_hz=35; Tracking_1C.dll_bw_hz=2.0; -Tracking_1C.order=3; +Tracking_1C.pll_bw_narrow_hz=5.0; +Tracking_1C.dll_bw_narrow_hz=0.50; +Tracking_1C.fll_bw_hz=10 +Tracking_1C.enable_fll_pull_in=true; +Tracking_1C.enable_fll_steady_state=false +Tracking_1C.high_dyn=true +Tracking_1C.dump=false +Tracking_1C.dump_filename=tracking_ch_ ;######### TELEMETRY DECODER GPS CONFIG ############ TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.dump=false ;######### OBSERVABLES CONFIG ############ -Observables.implementation=GPS_L1_CA_Observables +Observables.implementation=Hybrid_Observables Observables.dump=false -Observables.dump_filename=./observables.dat - ;######### PVT CONFIG ############ -PVT.implementation=GPS_L1_CA_PVT -PVT.averaging_depth=100 -PVT.flag_averaging=false -PVT.output_rate_ms=10 -PVT.display_rate_ms=500 -PVT.dump_filename=./PVT -PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; -PVT.flag_nmea_tty_port=false; -PVT.nmea_dump_devname=/dev/pts/4 +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single +PVT.iono_model=OFF +PVT.trop_model=OFF +PVT.raim_fde=1 +PVT.output_rate_ms=20; +PVT.display_rate_ms=500; +PVT.elevation_mask=0; PVT.flag_rtcm_server=false PVT.flag_rtcm_tty_port=false PVT.rtcm_dump_devname=/dev/pts/1 PVT.dump=false +PVT.dump_filename=./PVT diff --git a/docs/changelog.md b/docs/changelog.md index 228b27c78..c3ba94f56 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -54,7 +54,12 @@ SPDX-FileCopyrightText: 2011-2021 Carles Fernandez-Prades <carles.fernandez@cttc inconsistencies in the configuration file. - Fix segmentation fault if the RINEX output was disabled. - Added a feature that optionally enables the remote monitoring of GPS and - Galileo ephemeris using UDP and protobuffers. + Galileo ephemeris using UDP and + [Protocol Buffers](https://developers.google.com/protocol-buffers). +- Now building the software passing the `-DENABLE_FPGA=ON` to CMake does not + make the receiver unusable when running on non-FPGA-enabled platforms. On + FPGA-enabled platforms, now it is possible to run non-FPGA-enabled + configurations. diff --git a/docs/xml-schemas/gal_almanac_map.xsd b/docs/xml-schemas/gal_almanac_map.xsd index 2f6343fc3..26c82568b 100644 --- a/docs/xml-schemas/gal_almanac_map.xsd +++ b/docs/xml-schemas/gal_almanac_map.xsd @@ -17,18 +17,18 @@ <xs:complexType> <xs:sequence> <xs:element type="xs:byte" name="PRN"/> - <xs:element type="xs:int" name="toa"/> - <xs:element type="xs:byte" name="WNa"/> - <xs:element type="xs:byte" name="IODa"/> <xs:element type="xs:float" name="delta_i"/> + <xs:element type="xs:byte" name="toa"/> + <xs:element type="xs:byte" name="WNa"/> <xs:element type="xs:float" name="M_0"/> <xs:element type="xs:float" name="ecc"/> - <xs:element type="xs:float" name="delta_sqrtA"/> + <xs:element type="xs:float" name="sqrtA"/> <xs:element type="xs:float" name="OMEGA_0"/> <xs:element type="xs:float" name="omega"/> <xs:element type="xs:float" name="OMEGAdot"/> <xs:element type="xs:float" name="af0"/> <xs:element type="xs:float" name="af1"/> + <xs:element type="xs:byte" name="IODa"/> <xs:element type="xs:byte" name="E5b_HS"/> <xs:element type="xs:byte" name="E1B_HS"/> <xs:element type="xs:byte" name="E5a_HS"/> diff --git a/docs/xml-schemas/gps_almanac_map.xsd b/docs/xml-schemas/gps_almanac_map.xsd index dea16fd14..f6814c34e 100644 --- a/docs/xml-schemas/gps_almanac_map.xsd +++ b/docs/xml-schemas/gps_almanac_map.xsd @@ -26,10 +26,10 @@ <xs:element type="xs:float" name="OMEGA_0"/> <xs:element type="xs:float" name="omega"/> <xs:element type="xs:float" name="OMEGAdot"/> - <xs:element type="xs:byte" name="SV_health"/> - <xs:element type="xs:byte" name="AS_status"/> <xs:element type="xs:float" name="af0"/> <xs:element type="xs:float" name="af1"/> + <xs:element type="xs:byte" name="SV_health"/> + <xs:element type="xs:byte" name="AS_status"/> </xs:sequence> <xs:attribute type="xs:byte" name="class_id" use="optional"/> <xs:attribute type="xs:byte" name="tracking_level" use="optional"/> diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.cc b/src/algorithms/libs/rtklib/rtklib_conversions.cc index a8a7f81ba..e7a088941 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.cc +++ b/src/algorithms/libs/rtklib/rtklib_conversions.cc @@ -454,8 +454,7 @@ alm_t alm_to_rtklib(const Galileo_Almanac& gal_alm) toa.time = gal_alm.toa; toa.sec = 0.0; rtklib_alm.toa = toa; - rtklib_alm.A = 5440.588203494 + gal_alm.delta_sqrtA; - rtklib_alm.A = rtklib_alm.A * rtklib_alm.A; + rtklib_alm.A = gal_alm.sqrtA * gal_alm.sqrtA; rtklib_alm.e = gal_alm.ecc; rtklib_alm.i0 = (gal_alm.delta_i + 56.0 / 180.0) * GNSS_PI; rtklib_alm.OMG0 = gal_alm.OMEGA_0 * GNSS_PI; diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index c3d27001a..984144f0d 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -157,6 +157,8 @@ target_include_directories(signal_source_adapters if(ENABLE_FPGA OR ENABLE_AD9361) target_link_libraries(signal_source_adapters + PUBLIC + signal_source_libs PRIVATE core_libs ) diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc index 43e4461c0..6f6d03056 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -23,6 +23,7 @@ #include "GPS_L1_CA.h" #include "GPS_L5.h" #include "ad9361_manager.h" +#include "command_event.h" #include "configuration_interface.h" #include "gnss_sdr_flags.h" #include "gnss_sdr_string_literals.h" @@ -35,6 +36,7 @@ #include <exception> // for exceptions #include <fcntl.h> // for open, O_WRONLY #include <fstream> // for std::ifstream +#include <iomanip> // for std::setprecision #include <iostream> // for cout #include <string> // for string manipulation #include <thread> // for std::chrono @@ -48,8 +50,10 @@ using namespace std::string_literals; Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, const std::string &role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) - : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) + : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { + // initialize the variables that are used in real-time mode + const std::string default_gain_mode("slow_attack"); const double default_tx_attenuation_db = -10.0; const double default_manual_gain_rx1 = 64.0; @@ -92,14 +96,77 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con rf_shutdown_ = configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown); + // initialize the variables that are used in post-processing mode + + enable_DMA_ = false; + + const int l1_band = configuration->property("Channels_1C.count", 0) + + configuration->property("Channels_1B.count", 0); + + // by default the DMA transfers samples corresponding to two frequency bands to the FPGA + num_freq_bands_ = 2; + dma_buff_offset_pos_ = 0; + + // if only one input file is specified in the configuration file then: + // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels + // otherwise the DMA transfers the samples to the L2/L5 frequency band channels + if (filename1.empty()) + { + num_freq_bands_ = 1; + if (l1_band != 0) + { + dma_buff_offset_pos_ = 2; + } + } + + const double default_seconds_to_skip = 0.0; + + const std::string empty_string; + filename0 = configuration->property(role + ".filename", empty_string); + + // override value with commandline flag, if present + if (FLAGS_signal_source != "-") + { + filename0 = FLAGS_signal_source; + } + if (FLAGS_s != "-") + { + filename0 = FLAGS_s; + } + + if (filename0.empty()) + { + filename0 = configuration->property(role + ".filename0", empty_string); + filename1 = configuration->property(role + ".filename1", empty_string); + } + + samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); + + const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); + const size_t header_size = configuration->property(role + ".header_size", 0); + std::string item_type = "ibyte"; // for now only the ibyte format is supported + item_size_ = sizeof(int8_t); + repeat_ = configuration->property(role + ".repeat", false); + + if (seconds_to_skip > 0) + { + samples_to_skip_ = static_cast<int64_t>(seconds_to_skip * sample_rate_) * 2; + } + if (header_size > 0) + { + samples_to_skip_ += header_size; + } + + // check the switch status (determines real-time mode or post-processing mode) + + std::string device_io_name; // Switch UIO device file - // Switch UIO device file - std::string device_io_name; // find the uio device file corresponding to the switch. if (find_uio_dev_file_name(device_io_name, switch_device_name, 0) < 0) { - std::cout << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << std::endl; - throw std::exception(); + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << '\n'; + item_size_ = 0; + return; } switch_position_ = configuration->property(role + ".switch_position", 0); @@ -113,55 +180,102 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con switch_fpga = std::make_shared<Fpga_Switch>(device_io_name); switch_fpga->set_switch_position(switch_position_); - item_size_ = sizeof(gr_complex); - - std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; - - enable_ovf_check_buffer_monitor_active_ = false; // check buffer overflow and buffer monitor disabled by default - if (switch_position_ == 0) // Inject file(s) via DMA { enable_DMA_ = true; - const std::string empty_string; - filename_rx1 = configuration->property(role + ".filename", empty_string); - // override value with commandline flag, if present - if (FLAGS_signal_source != "-") + if (samples_ == 0) // read all file { - filename_rx1 = FLAGS_signal_source; - } - if (FLAGS_s != "-") - { - filename_rx1 = FLAGS_s; + /*! + * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. + * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the + * valve block + */ + std::ifstream file(filename0.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); + } + else + { + std::cerr << "SignalSource: Unable to open the samples file " << filename0.c_str() << '\n'; + item_size_ = 0; + return; + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename0 << ", which contains " << static_cast<double>(size) << " [bytes]\n"; + std::cout.precision(ss); + + if (size > 0) + { + const int64_t bytes_to_skip = samples_to_skip_ * item_size_; + const int64_t bytes_to_process = static_cast<int64_t>(size) - bytes_to_skip; + samples_ = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms + } + + if (!filename1.empty()) + { + std::ifstream file(filename1.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); + } + else + { + std::cerr << "SignalSource: Unable to open the samples file " << filename1.c_str() << '\n'; + item_size_ = 0; + return; + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename1 << ", which contains " << static_cast<double>(size) << " [bytes]\n"; + std::cout.precision(ss); + + uint64_t samples_rx2 = 0; + if (size > 0) + { + const int64_t bytes_to_skip = samples_to_skip_ * item_size_; + const int64_t bytes_to_process = static_cast<int64_t>(size) - bytes_to_skip; + samples_rx2 = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms + } + samples_ = std::min(samples_, samples_rx2); + } } - if (filename_rx1.empty()) - { - filename_rx1 = configuration->property(role + ".filename0", empty_string); - filename_rx2 = configuration->property(role + ".filename1", empty_string); - } - const int l1_band = configuration->property("Channels_1C.count", 0) + - configuration->property("Channels_1B.count", 0); + CHECK(samples_ > 0) << "File does not contain enough samples to process."; + double signal_duration_s = (static_cast<double>(samples_) * (1 / static_cast<double>(sample_rate_))) / 2.0; - const int l2_band = configuration->property("Channels_L5.count", 0) + - configuration->property("Channels_5X.count", 0) + - configuration->property("Channels_2S.count", 0); + DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; + std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; - if (l1_band != 0) + if (filename1.empty()) { - freq_band = "L1"; + DLOG(INFO) << "File source filename " << filename0; } - if (l2_band != 0 && l1_band == 0) + else { - freq_band = "L2"; - } - if (l1_band != 0 && l2_band != 0) - { - freq_band = "L1L2"; + DLOG(INFO) << "File source filename rx1 " << filename0; + DLOG(INFO) << "File source filename rx2 " << filename1; } + DLOG(INFO) << "Samples " << samples_; + DLOG(INFO) << "Sampling frequency " << sample_rate_; + DLOG(INFO) << "Item type " << item_type; + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "Repeat " << repeat_; } if (switch_position_ == 2) // Real-time via AD9361 { + std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; + + enable_ovf_check_buffer_monitor_active_ = false; // check buffer overflow and buffer monitor disabled by default + // some basic checks if ((rf_port_select_ != "A_BALANCED") and (rf_port_select_ != "B_BALANCED") and (rf_port_select_ != "A_N") and (rf_port_select_ != "B_N") and (rf_port_select_ != "B_P") and (rf_port_select_ != "C_N") and (rf_port_select_ != "C_P") and (rf_port_select_ != "TX_MONITOR1") and (rf_port_select_ != "TX_MONITOR2") and (rf_port_select_ != "TX_MONITOR1_2")) { @@ -262,7 +376,9 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con } catch (const std::runtime_error &e) { - std::cout << "Exception cached when configuring the RX chain: " << e.what() << '\n'; + std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; + item_size_ = 0; + return; } // LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION if (enable_dds_lo_ == true) @@ -295,7 +411,9 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con } catch (const std::runtime_error &e) { - std::cout << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; + std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; + item_size_ = 0; + return; } } @@ -311,12 +429,12 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con // find the uio device file corresponding to the buffer monitor if (find_uio_dev_file_name(device_io_name_buffer_monitor, buffer_monitor_device_name, 0) < 0) { - std::cout << "Cannot find the FPGA uio device file corresponding to device name " << buffer_monitor_device_name << std::endl; - throw std::exception(); + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << buffer_monitor_device_name << '\n'; + item_size_ = 0; + return; } - uint32_t num_freq_bands = (freq_band.compare("L1L2")) ? 1 : 2; - buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(device_io_name_buffer_monitor, num_freq_bands, dump_, dump_filename); + buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(device_io_name_buffer_monitor, num_freq_bands_, dump_, dump_filename); thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); } @@ -329,15 +447,17 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con // find the uio device file corresponding to the dynamic bit selector 0 module. if (find_uio_dev_file_name(device_io_name_dyn_bit_sel_0, dyn_bit_sel_device_name, 0) < 0) { - std::cout << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << std::endl; - throw std::exception(); + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n'; + item_size_ = 0; + return; } // find the uio device file corresponding to the dynamic bit selector 1 module. if (find_uio_dev_file_name(device_io_name_dyn_bit_sel_1, dyn_bit_sel_device_name, 1) < 0) { - std::cout << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << std::endl; - throw std::exception(); + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n'; + item_size_ = 0; + return; } dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(device_io_name_dyn_bit_sel_0, device_io_name_dyn_bit_sel_1); thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); @@ -418,202 +538,177 @@ Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() } } + void Ad9361FpgaSignalSource::start() { - thread_file_to_dma = std::thread([&] { run_DMA_process(freq_band, filename_rx1, filename_rx2); }); + thread_file_to_dma = std::thread([&] { run_DMA_process(filename0, filename1, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); } -void Ad9361FpgaSignalSource::run_DMA_process(const std::string &FreqBand, const std::string &Filename1, const std::string &Filename2) +void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0, const std::string &filename1, uint64_t &samples_to_skip, size_t &item_size, uint64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue<pmt::pmt_t> *queue) { - const int MAX_INPUT_SAMPLES_TOTAL = 16384; - int max_value = 0; std::ifstream infile1; infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); + // open the files try { - infile1.open(Filename1, std::ios::binary); + infile1.open(filename0, std::ios::binary); } catch (const std::ifstream::failure &e) { - std::cerr << "Exception opening file " << Filename1 << '\n'; + std::cerr << "Exception opening file " << filename0 << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); return; } std::ifstream infile2; - infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); + if (!filename1.empty()) + { + infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + infile2.open(filename1, std::ios::binary); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception opening file " << filename1 << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + } + + // skip the initial samples if needed + uint64_t bytes_to_skeep = samples_to_skip * item_size; try { - infile2.open(Filename2, std::ios::binary); + infile1.ignore(bytes_to_skeep); } catch (const std::ifstream::failure &e) { - // could not exist - } - - // rx signal - std::vector<int8_t> input_samples(MAX_INPUT_SAMPLES_TOTAL * 2); - std::vector<int8_t> input_samples2(MAX_INPUT_SAMPLES_TOTAL * 2); - std::vector<int8_t> input_samples_dma(MAX_INPUT_SAMPLES_TOTAL * 2 * 2); - - int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1 - int nread_elements2 = 0; // num bytes read from the file corresponding to frequency band 2 - int file_completed = 0; - int num_transferred_bytes; - - //************************************************************************** - // Open DMA device - //************************************************************************** - const int tx_fd = open("/dev/loop_tx", O_WRONLY); - if (tx_fd < 0) - { - std::cout << "Cannot open loop device\n"; + std::cerr << "Exception skipping initial samples file " << filename0 << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); return; } - //************************************************************************** - // Open input file - //************************************************************************** - int nsamples = 0; - - while (file_completed == 0) + if (!filename1.empty()) { - unsigned int dma_index = 0; - - if (FreqBand == "L1") + try { - try - { - infile1.read(reinterpret_cast<char *>(input_samples.data()), MAX_INPUT_SAMPLES_TOTAL * 2); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception reading file " << Filename1 << '\n'; - } - if (infile1) - { - nread_elements = MAX_INPUT_SAMPLES_TOTAL * 2; - } - else - { - nread_elements = infile1.gcount(); - } - nsamples += (nread_elements / 2); - - for (int index0 = 0; index0 < (nread_elements); index0 += 2) - { - // channel 1 (queue 1) - input_samples_dma[dma_index] = 0; - input_samples_dma[dma_index + 1] = 0; - // channel 0 (queue 0) - input_samples_dma[dma_index + 2] = input_samples[index0]; - input_samples_dma[dma_index + 3] = input_samples[index0 + 1]; - - dma_index += 4; - } + infile2.ignore(bytes_to_skeep); } - else if (FreqBand == "L2") + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename1 << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + } + + + // rx signal vectors + std::vector<int8_t> input_samples(sample_block_size * 2); // complex samples + std::vector<int8_t> input_samples_dma(sample_block_size * 4); // complex samples, two frequency bands + + int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1 + bool run_DMA = true; + int num_transferred_bytes; + + // Open DMA device + const int tx_fd = open("/dev/loop_tx", O_WRONLY); + if (tx_fd < 0) + { + std::cerr << "Cannot open loop device\n"; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + + // if only one frequency band is used then clear the samples corresponding to the unused frequency band + uint32_t dma_index = 0; + if (num_freq_bands_ == 1) + { + // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. + for (int index0 = 0; index0 < (nread_elements); index0 += 2) + { + input_samples_dma[dma_index + (2 - dma_buff_offset_pos)] = 0; + input_samples_dma[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; + dma_index += 4; + } + } + + uint64_t nbytes_remaining = samples * item_size; + uint32_t read_buffer_size = sample_block_size * 2; // complex samples + + // run the DMA + while (run_DMA) + { + if (nbytes_remaining < read_buffer_size) + { + read_buffer_size = nbytes_remaining; + } + nbytes_remaining = nbytes_remaining - read_buffer_size; + + // read filename 0 + try + { + infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception reading file " << filename0 << '\n'; + break; + } + if (infile1) + { + nread_elements = read_buffer_size; + } + else + { + // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN + nread_elements = infile1.gcount(); + } + + for (int index0 = 0; index0 < (nread_elements); index0 += 2) + { + // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands + input_samples_dma[dma_index + dma_buff_offset_pos] = input_samples[index0]; + input_samples_dma[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; + dma_index += 4; + } + + // read filename 1 (if enabled) + dma_index = 0; + if (num_freq_bands_ > 1) { try { - infile1.read(reinterpret_cast<char *>(input_samples.data()), MAX_INPUT_SAMPLES_TOTAL * 2); + infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); } catch (const std::ifstream::failure &e) { - std::cerr << "Exception reading file " << Filename1 << '\n'; + std::cerr << "Exception reading file " << filename1 << '\n'; + break; } if (infile1) { - nread_elements = MAX_INPUT_SAMPLES_TOTAL * 2; + nread_elements = read_buffer_size; } else { + // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN nread_elements = infile1.gcount(); } - nsamples += (nread_elements / 2); for (int index0 = 0; index0 < (nread_elements); index0 += 2) { - // channel 1 (queue 1) + // filename2 is never the L1 band input_samples_dma[dma_index] = input_samples[index0]; input_samples_dma[dma_index + 1] = input_samples[index0 + 1]; - // channel 0 (queue 0) - input_samples_dma[dma_index + 2] = 0; - input_samples_dma[dma_index + 3] = 0; - - dma_index += 4; - } - } - else if (FreqBand == "L1L2") - { - try - { - infile1.read(reinterpret_cast<char *>(input_samples.data()), MAX_INPUT_SAMPLES_TOTAL * 2); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception reading file " << Filename1 << '\n'; - } - if (infile1) - { - nread_elements = MAX_INPUT_SAMPLES_TOTAL * 2; - } - else - { - nread_elements = infile1.gcount(); - } - try - { - infile2.read(reinterpret_cast<char *>(input_samples2.data()), MAX_INPUT_SAMPLES_TOTAL * 2); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception reading file " << Filename1 << '\n'; - } - if (infile2) - { - nread_elements2 = MAX_INPUT_SAMPLES_TOTAL * 2; - } - else - { - nread_elements2 = infile2.gcount(); - } - - if (nread_elements > nread_elements2) - { - nread_elements = nread_elements2; // take the smallest - } - - nsamples += (nread_elements / 2); - - for (int index0 = 0; index0 < (nread_elements); index0 += 2) - { - if (input_samples[index0] > max_value) - { - max_value = input_samples[index0]; - } - else if (-input_samples[index0] > max_value) - { - max_value = -input_samples[index0]; - } - - if (input_samples[index0 + 1] > max_value) - { - max_value = input_samples[index0 + 1]; - } - else if (-input_samples[index0 + 1] > max_value) - { - max_value = -input_samples[index0 + 1]; - } - - // channel 1 (queue 1) - input_samples_dma[dma_index] = input_samples2[index0]; - input_samples_dma[dma_index + 1] = input_samples2[index0 + 1]; - // channel 0 (queue 0) - input_samples_dma[dma_index + 2] = input_samples[index0]; - input_samples_dma[dma_index + 3] = input_samples[index0 + 1]; - dma_index += 4; } } @@ -625,21 +720,75 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &FreqBand, const if (num_bytes_sent != num_transferred_bytes) { std::cerr << "Error: DMA could not send all the required samples\n"; + break; } // Throttle the DMA std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - if (nread_elements != MAX_INPUT_SAMPLES_TOTAL * 2) + if (nbytes_remaining == 0) { - file_completed = 1; - } + if (repeat) + { + // read the file again + nbytes_remaining = samples * item_size; + read_buffer_size = sample_block_size * 2; + try + { + infile1.seekg(0); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0 << '\n'; + break; + } + // skip the initial samples if needed + uint64_t bytes_to_skeep = samples_to_skip * item_size; + try + { + infile1.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename0 << '\n'; + break; + } + + if (!filename1.empty()) + { + try + { + infile2.seekg(0); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1 << '\n'; + break; + } + + try + { + infile2.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename1 << '\n'; + break; + } + } + } + else + { + // the input file is completely processed. Stop the receiver. + run_DMA = false; + } + } std::unique_lock<std::mutex> lock(dma_mutex); if (enable_DMA_ == false) { - file_completed = true; + run_DMA = false; } lock.unlock(); } @@ -652,15 +801,26 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &FreqBand, const try { infile1.close(); - if (FreqBand == "L1L2") - { - infile2.close(); - } } catch (const std::ifstream::failure &e) { - std::cerr << "Exception closing files " << Filename1 << " and " << Filename2 << '\n'; + std::cerr << "Exception closing file " << filename0 << '\n'; } + + if (num_freq_bands_ > 1) + { + try + { + infile2.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception closing file " << filename1 << '\n'; + } + } + + // Stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); } @@ -682,6 +842,7 @@ void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process() } } + void Ad9361FpgaSignalSource::run_buffer_monitor_process() { bool enable_ovf_check_buffer_monitor_active = true; diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h index e9e1dccf0..2818a6722 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h @@ -67,15 +67,22 @@ private: const std::string buffer_monitor_device_name = "buffer_monitor"; // buffer monitor device name const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); // perform dynamic bit selection every 500 ms by default - static const uint32_t Gain_control_period_ms = 500; + const uint32_t Gain_control_period_ms = 500; // check buffer overflow and perform buffer monitoring every 1s by default - static const uint32_t buffer_monitor_period_ms = 1000; + const uint32_t buffer_monitor_period_ms = 1000; // buffer overflow and buffer monitoring initial delay - static const uint32_t buffer_monitoring_initial_delay_ms = 2000; + const uint32_t buffer_monitoring_initial_delay_ms = 2000; + // sample block size when running in post-processing mode + const int sample_block_size = 16384; - void run_DMA_process(const std::string &FreqBand, - const std::string &Filename1, - const std::string &Filename2); + void run_DMA_process(const std::string &Filename1, + const std::string &Filename2, + uint64_t &samples_to_skip, + size_t &item_size, + uint64_t &samples, + bool &repeat, + uint32_t &dma_buff_offset_pos, + Concurrent_Queue<pmt::pmt_t> *queue); void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); @@ -95,9 +102,8 @@ private: std::string filter_file_; std::string filter_source_; std::string filter_filename_; - std::string filename_rx1; - std::string filename_rx2; - std::string freq_band; + std::string filename0; + std::string filename1; std::mutex dma_mutex; std::mutex dynamic_bit_selection_mutex; @@ -133,9 +139,17 @@ private: bool enable_DMA_; bool enable_dynamic_bit_selection_; bool enable_ovf_check_buffer_monitor_active_; - bool enable_ovf_check_buffer_monitor_; bool dump_; bool rf_shutdown_; + + // post-processing mode + uint64_t samples_; + uint64_t samples_to_skip_; + bool repeat_; + uint32_t num_freq_bands_; + uint32_t dma_buff_offset_pos_; + + Concurrent_Queue<pmt::pmt_t> *queue_; }; diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc index b5799f9d2..e98988137 100644 --- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc +++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc @@ -23,7 +23,6 @@ */ #include "fpga_buffer_monitor.h" -#include "command_event.h" #include "gnss_sdr_create_directory.h" #include "gnss_sdr_filesystem.h" #include <glog/logging.h> diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h index 778585a58..c9631c0eb 100644 --- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h +++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h @@ -25,10 +25,8 @@ #ifndef GNSS_SDR_FPGA_BUFFER_MONITOR_H #define GNSS_SDR_FPGA_BUFFER_MONITOR_H -#include "concurrent_queue.h" -#include <pmt/pmt.h> // pmt -#include <cstdint> // for int32_t -#include <fstream> // for string, ofstream +#include <cstdint> // for int32_t +#include <fstream> // for string, ofstream /** \addtogroup Signal_Source * \{ */ diff --git a/src/core/libs/gnss_sdr_supl_client.cc b/src/core/libs/gnss_sdr_supl_client.cc index e5af67588..d09b3c099 100644 --- a/src/core/libs/gnss_sdr_supl_client.cc +++ b/src/core/libs/gnss_sdr_supl_client.cc @@ -201,9 +201,9 @@ void Gnss_Sdr_Supl_Client::read_supl_data() { /* TS 44.031: GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation */ gps_time.tow = static_cast<double>(assist.time.gps_tow) * 0.08; - gps_time.d_Week = static_cast<double>(assist.time.gps_week); - gps_time.d_tv_sec = static_cast<double>(assist.time.stamp.tv_sec); - gps_time.d_tv_usec = static_cast<double>(assist.time.stamp.tv_usec); + gps_time.week = static_cast<double>(assist.time.gps_week); + gps_time.seconds = static_cast<double>(assist.time.stamp.tv_sec); + gps_time.microseconds = static_cast<double>(assist.time.stamp.tv_usec); gps_time.valid = true; } @@ -871,7 +871,7 @@ bool Gnss_Sdr_Supl_Client::read_gal_almanac_from_gsa(const std::string& file_nam gal_alm.delta_i = std::stod(almanac.child("almanac").child_value("deltai")); gal_alm.M_0 = std::stod(almanac.child("almanac").child_value("m0")); gal_alm.ecc = std::stod(almanac.child("almanac").child_value("ecc")); - gal_alm.delta_sqrtA = std::stod(almanac.child("almanac").child_value("aSqRoot")); + gal_alm.sqrtA = std::stod(almanac.child("almanac").child_value("aSqRoot")); gal_alm.OMEGA_0 = std::stod(almanac.child("almanac").child_value("omega0")); gal_alm.omega = std::stod(almanac.child("almanac").child_value("w")); gal_alm.OMEGAdot = std::stod(almanac.child("almanac").child_value("omegaDot")); diff --git a/src/core/libs/uio_fpga.cc b/src/core/libs/uio_fpga.cc index c8a143a90..9d436d7c3 100644 --- a/src/core/libs/uio_fpga.cc +++ b/src/core/libs/uio_fpga.cc @@ -19,10 +19,11 @@ #include "gnss_sdr_filesystem.h" #include <algorithm> // sort #include <cstdlib> // atoi, size_t -#include <fstream> // ifstream -#include <iostream> // cout -#include <locale> // isdigit -#include <sstream> // std::stringstream +#include <exception> +#include <fstream> // ifstream +#include <iostream> // cout +#include <locale> // isdigit +#include <sstream> // std::stringstream #include <vector> @@ -188,7 +189,15 @@ int32_t find_uio_num(const std::string &device_name, uint32_t device_num) int32_t find_uio_dev_file_name(std::string &device_file_name, const std::string &device_name, uint32_t device_num) { - int32_t uio_num = find_uio_num(device_name, device_num); + int32_t uio_num = 0; + try + { + uio_num = find_uio_num(device_name, device_num); + } + catch (const std::exception &e) + { + return -1; + } if (uio_num >= 0) { std::stringstream device_file_name_tmp; diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index 557b53ab2..fb62f9d86 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -209,7 +209,7 @@ void ControlThread::init() // Make an educated guess time_t rawtime; time(&rawtime); - agnss_ref_time_.d_tv_sec = rawtime; + agnss_ref_time_.seconds = rawtime; agnss_ref_time_.valid = true; } else @@ -220,8 +220,8 @@ void ControlThread::init() }; if (strptime(ref_time_str.c_str(), "%d/%m/%Y %H:%M:%S", &tm) != nullptr) { - agnss_ref_time_.d_tv_sec = timegm(&tm); - if (agnss_ref_time_.d_tv_sec > 0) + agnss_ref_time_.seconds = timegm(&tm); + if (agnss_ref_time_.seconds > 0) { agnss_ref_time_.valid = true; } @@ -883,7 +883,7 @@ void ControlThread::assist_GNSS() time_t ref_rx_utc_time = 0; if (agnss_ref_time_.valid == true) { - ref_rx_utc_time = static_cast<time_t>(agnss_ref_time_.d_tv_sec); + ref_rx_utc_time = static_cast<time_t>(agnss_ref_time_.seconds); } const std::vector<std::pair<int, Gnss_Satellite>> visible_sats = get_visible_sats(ref_rx_utc_time, ref_LLH); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 65fe1162a..f074cb1e0 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -75,6 +75,7 @@ GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr<ConfigurationInterface> configurati configuration_ = std::move(configuration); queue_ = std::move(queue); multiband_ = GNSSFlowgraph::is_multiband(); + enable_fpga_offloading_ = configuration_->property("GNSS-SDR.enable_FPGA", false); init(); } @@ -107,17 +108,22 @@ void GNSSFlowgraph::init() { std::cout << "Creating source " << i << '\n'; sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), i)); - auto& src = sig_source_.back(); - auto RF_Channels = src->getRfChannels(); - std::cout << "RF Channels " << RF_Channels << '\n'; - for (auto j = 0U; j < RF_Channels; ++j) + if (enable_fpga_offloading_ == false) { - sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); - signal_conditioner_ID++; + auto& src = sig_source_.back(); + auto RF_Channels = src->getRfChannels(); + std::cout << "RF Channels " << RF_Channels << '\n'; + for (auto j = 0U; j < RF_Channels; ++j) + { + sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); + signal_conditioner_ID++; + } } } - - signal_conditioner_connected_ = std::vector<bool>(sig_conditioner_.size(), false); + if (!sig_conditioner_.empty()) + { + signal_conditioner_connected_ = std::vector<bool>(sig_conditioner_.size(), false); + } observables_ = block_factory->GetObservables(configuration_.get()); @@ -242,13 +248,14 @@ void GNSSFlowgraph::start() return; } -#if ENABLE_FPGA - // start the DMA if the receiver is in post-processing mode - if (configuration_->property(sig_source_.at(0)->role() + ".switch_position", 0) == 0) + if (enable_fpga_offloading_ == true) { - sig_source_.at(0)->start(); + // start the DMA if the receiver is in post-processing mode + if (configuration_->property(sig_source_.at(0)->role() + ".switch_position", 0) == 0) + { + sig_source_.at(0)->start(); + } } -#endif running_ = true; } @@ -261,10 +268,12 @@ void GNSSFlowgraph::stop() chan->stop_channel(); // stop the acquisition or tracking operation } top_block_->stop(); -#if ENABLE_FPGA -#else - top_block_->wait(); -#endif + + if (enable_fpga_offloading_ == false) + { + top_block_->wait(); + } + running_ = false; } @@ -293,16 +302,28 @@ void GNSSFlowgraph::connect() } #if ENABLE_FPGA - if (connect_fpga_flowgraph() != 0) + if (enable_fpga_offloading_ == true) { - LOG(ERROR) << "Unable to connect flowgraph with FPFA off-loading"; - print_help(); - return; + if (connect_fpga_flowgraph() != 0) + { + std::cerr << "Unable to connect flowgraph with FPGA off-loading\n"; + print_help(); + return; + } + } + else + { + if (connect_desktop_flowgraph() != 0) + { + std::cerr << "Unable to connect flowgraph\n"; + print_help(); + return; + } } #else if (connect_desktop_flowgraph() != 0) { - LOG(ERROR) << "Unable to connect flowgraph"; + std::cerr << "Unable to connect flowgraph\n"; print_help(); return; } @@ -326,9 +347,19 @@ void GNSSFlowgraph::disconnect() connected_ = false; #if ENABLE_FPGA - if (disconnect_fpga_flowgraph() != 0) + if (enable_fpga_offloading_ == true) { - return; + if (disconnect_fpga_flowgraph() != 0) + { + return; + } + } + else + { + if (disconnect_desktop_flowgraph() != 0) + { + return; + } } #else if (disconnect_desktop_flowgraph() != 0) @@ -343,9 +374,6 @@ void GNSSFlowgraph::disconnect() int GNSSFlowgraph::connect_desktop_flowgraph() { -#if ENABLE_FPGA - return 0; -#else // Connect blocks to the top_block if (connect_signal_sources() != 0) { @@ -424,15 +452,11 @@ int GNSSFlowgraph::connect_desktop_flowgraph() LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration has been successfully connected"; return 0; -#endif } int GNSSFlowgraph::disconnect_desktop_flowgraph() { -#if ENABLE_FPGA - return 0; -#else // Disconnect blocks between them if (disconnect_signal_sources_from_signal_conditioners() != 0) { @@ -491,14 +515,32 @@ int GNSSFlowgraph::disconnect_desktop_flowgraph() } return 0; -#endif } #if ENABLE_FPGA int GNSSFlowgraph::connect_fpga_flowgraph() { + // Check that the Signal Source has been instantiated successfully + + for (auto& src : sig_source_) + { + if (src == nullptr) + { + help_hint_ += " * Undefined SignalSource.implementation in the configuration file.\n"; + return 1; + } + if (src->item_size() == 0) + { + help_hint_ += " * The global configuration parameter GNSS-SDR.enable_FPGA is set to true,\n"; + help_hint_ += " but gnss-sdr does not appear to be executed in an FPGA-equipped platform,\n"; + help_hint_ += " or there are some required files that are missing.\n"; + return 1; + } + } + // Connect blocks to the top_block + if (connect_channels() != 0) { return 1; @@ -519,19 +561,9 @@ int GNSSFlowgraph::connect_fpga_flowgraph() // Connect the counter if (sig_source_.at(0) != nullptr) { - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + if (connect_fpga_sample_counter() != 0) { - if (connect_sample_counter() != 0) - { - return 1; - } - } - else - { - if (connect_fpga_sample_counter() != 0) - { - return 1; - } + return 1; } } else @@ -546,11 +578,6 @@ int GNSSFlowgraph::connect_fpga_flowgraph() return 1; } - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) - { - check_signal_conditioners(); - } - assign_channels(); if (connect_observables_to_pvt() != 0) @@ -572,27 +599,9 @@ int GNSSFlowgraph::connect_fpga_flowgraph() int GNSSFlowgraph::disconnect_fpga_flowgraph() { - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + if (disconnect_fpga_sample_counter() != 0) { - if (disconnect_signal_sources_from_signal_conditioners() != 0) - { - return 1; - } - } - - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) - { - if (disconnect_sample_counter() != 0) - { - return 1; - } - } - else - { - if (disconnect_fpga_sample_counter() != 0) - { - return 1; - } + return 1; } if (disconnect_monitors() != 0) @@ -610,16 +619,6 @@ int GNSSFlowgraph::disconnect_fpga_flowgraph() return 1; } - if (disconnect_signal_sources() != 0) - { - return 1; - } - - if (disconnect_signal_conditioners() != 0) - { - return 1; - } - if (disconnect_channels() != 0) { return 1; @@ -971,7 +970,16 @@ int GNSSFlowgraph::connect_fpga_sample_counter() } catch (const std::exception& e) { - LOG(ERROR) << "Can't connect FPGA sample counter: " << e.what(); + std::string reported_error(e.what()); + if (std::string::npos != reported_error.find(std::string("filesystem"))) + { + help_hint_ += " * The global configuration parameter GNSS-SDR.enable_FPGA is set to true,\n"; + help_hint_ += " but gnss-sdr does not appear to be executed in an FPGA-equipped platform.\n"; + } + else + { + LOG(ERROR) << reported_error; + } top_block_->disconnect_all(); return 1; } @@ -999,6 +1007,13 @@ int GNSSFlowgraph::disconnect_fpga_sample_counter() int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() { + if (enable_fpga_offloading_) + { + help_hint_ += " * The global configuration parameter GNSS-SDR.enable_FPGA is set to true,\n"; + help_hint_ += " but gnss-sdr was not compiled with the -DENABLE_FPGA=ON building option.\n"; + top_block_->disconnect_all(); + return 1; + } unsigned int signal_conditioner_ID = 0; for (int i = 0; i < sources_count_; i++) { diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index 59086a366..aea6c94e0 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -297,6 +297,7 @@ private: bool enable_monitor_; bool enable_acquisition_monitor_; bool enable_tracking_monitor_; + bool enable_fpga_offloading_; }; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 6486d8aaa..224dbe361 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -27,6 +27,7 @@ set(SYSTEM_PARAMETERS_SOURCES ) set(SYSTEM_PARAMETERS_HEADERS + gnss_almanac.h gnss_ephemeris.h gnss_satellite.h gnss_signal.h diff --git a/src/core/system_parameters/agnss_ref_time.h b/src/core/system_parameters/agnss_ref_time.h index df3859aaa..06bdd79d0 100644 --- a/src/core/system_parameters/agnss_ref_time.h +++ b/src/core/system_parameters/agnss_ref_time.h @@ -39,9 +39,9 @@ public: Agnss_Ref_Time() = default; double tow{}; - double d_Week{}; - double d_tv_sec{}; - double d_tv_usec{}; + double week{}; + double seconds{}; + double microseconds{}; bool valid{}; template <class Archive> @@ -56,9 +56,9 @@ public: { }; archive& BOOST_SERIALIZATION_NVP(tow); - archive& BOOST_SERIALIZATION_NVP(d_Week); - archive& BOOST_SERIALIZATION_NVP(d_tv_sec); - archive& BOOST_SERIALIZATION_NVP(d_tv_usec); + archive& BOOST_SERIALIZATION_NVP(week); + archive& BOOST_SERIALIZATION_NVP(seconds); + archive& BOOST_SERIALIZATION_NVP(microseconds); archive& BOOST_SERIALIZATION_NVP(valid); } }; diff --git a/src/core/system_parameters/beidou_dnav_almanac.h b/src/core/system_parameters/beidou_dnav_almanac.h index 37d7e33da..03610990f 100644 --- a/src/core/system_parameters/beidou_dnav_almanac.h +++ b/src/core/system_parameters/beidou_dnav_almanac.h @@ -18,6 +18,7 @@ #ifndef GNSS_SDR_BEIDOU_DNAV_ALMANAC_H #define GNSS_SDR_BEIDOU_DNAV_ALMANAC_H +#include "gnss_almanac.h" #include <boost/serialization/nvp.hpp> /** \addtogroup Core @@ -29,7 +30,7 @@ /*! * \brief This class is a storage for the BeiDou D1 almanac */ -class Beidou_Dnav_Almanac +class Beidou_Dnav_Almanac : public Gnss_Almanac { public: /*! @@ -37,18 +38,7 @@ public: */ Beidou_Dnav_Almanac() = default; - unsigned int PRN{}; //!< SV PRN NUMBER - double delta_i{}; - double toa{}; //!< Almanac data reference time of week [s] - double M_0{}; //!< Mean Anomaly at Reference Time [semi-circles] - double ecc{}; //!< Eccentricity [dimensionless] - double sqrtA{}; //!< Square Root of the Semi-Major Axis [sqrt(m)] - double OMEGA_0{}; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double omega{}; //!< Argument of Perigee [semi-cicles] - double OMEGAdot{}; //!< Rate of Right Ascension [semi-circles/s] - int SV_health{}; //!< SV Health - double af0{}; //!< Coefficient 0 of code phase offset model [s] - double af1{}; //!< Coefficient 1 of code phase offset model [s/s] + int SV_health{}; //!< SV Health template <class Archive> @@ -60,17 +50,16 @@ public: ar& BOOST_SERIALIZATION_NVP(PRN); ar& BOOST_SERIALIZATION_NVP(delta_i); ar& BOOST_SERIALIZATION_NVP(toa); - // ar& BOOST_SERIALIZATION_NVP(WNa); + ar& BOOST_SERIALIZATION_NVP(WNa); ar& BOOST_SERIALIZATION_NVP(M_0); ar& BOOST_SERIALIZATION_NVP(ecc); ar& BOOST_SERIALIZATION_NVP(sqrtA); ar& BOOST_SERIALIZATION_NVP(OMEGA_0); ar& BOOST_SERIALIZATION_NVP(omega); ar& BOOST_SERIALIZATION_NVP(OMEGAdot); - ar& BOOST_SERIALIZATION_NVP(SV_health); - // ar& BOOST_SERIALIZATION_NVP(AS_status); ar& BOOST_SERIALIZATION_NVP(af0); ar& BOOST_SERIALIZATION_NVP(af1); + ar& BOOST_SERIALIZATION_NVP(SV_health); } }; diff --git a/src/core/system_parameters/galileo_almanac.h b/src/core/system_parameters/galileo_almanac.h index 5799d2be4..a76a3af66 100644 --- a/src/core/system_parameters/galileo_almanac.h +++ b/src/core/system_parameters/galileo_almanac.h @@ -18,8 +18,8 @@ #ifndef GNSS_SDR_GALILEO_ALMANAC_H #define GNSS_SDR_GALILEO_ALMANAC_H +#include "gnss_almanac.h" #include <boost/serialization/nvp.hpp> -#include <cstdint> /** \addtogroup Core * \{ */ @@ -30,7 +30,7 @@ /*! * \brief This class is a storage for the Galileo SV ALMANAC data */ -class Galileo_Almanac +class Galileo_Almanac : public Gnss_Almanac { public: /*! @@ -38,19 +38,7 @@ public: */ Galileo_Almanac() = default; - uint32_t PRN{}; //!< SV PRN NUMBER - int32_t toa{}; - int32_t WNa{}; int32_t IODa{}; - double delta_i{}; //!< Inclination at reference time relative to i0 = 56ยบ [semi-circles] - double M_0{}; //!< Mean Anomaly at Reference Time [semi-circles] - double ecc{}; //!< Eccentricity [dimensionless] - double delta_sqrtA{}; //!< Square Root of the Semi-Major Axis [sqrt(m)] - double OMEGA_0{}; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double omega{}; //!< Argument of Perigee [semi-cicles] - double OMEGAdot{}; //!< Rate of Right Ascension [semi-circles/s] - double af0{}; //!< Coefficient 0 of code phase offset model [s] - double af1{}; //!< Coefficient 1 of code phase offset model [s/s] int32_t E5b_HS{}; int32_t E1B_HS{}; int32_t E5a_HS{}; @@ -63,18 +51,18 @@ public: { }; ar& BOOST_SERIALIZATION_NVP(PRN); + ar& BOOST_SERIALIZATION_NVP(delta_i); ar& BOOST_SERIALIZATION_NVP(toa); ar& BOOST_SERIALIZATION_NVP(WNa); - ar& BOOST_SERIALIZATION_NVP(IODa); - ar& BOOST_SERIALIZATION_NVP(delta_i); ar& BOOST_SERIALIZATION_NVP(M_0); ar& BOOST_SERIALIZATION_NVP(ecc); - ar& BOOST_SERIALIZATION_NVP(delta_sqrtA); + ar& BOOST_SERIALIZATION_NVP(sqrtA); ar& BOOST_SERIALIZATION_NVP(OMEGA_0); ar& BOOST_SERIALIZATION_NVP(omega); ar& BOOST_SERIALIZATION_NVP(OMEGAdot); ar& BOOST_SERIALIZATION_NVP(af0); ar& BOOST_SERIALIZATION_NVP(af1); + ar& BOOST_SERIALIZATION_NVP(IODa); ar& BOOST_SERIALIZATION_NVP(E5b_HS); ar& BOOST_SERIALIZATION_NVP(E1B_HS); ar& BOOST_SERIALIZATION_NVP(E5a_HS); diff --git a/src/core/system_parameters/galileo_almanac_helper.cc b/src/core/system_parameters/galileo_almanac_helper.cc index f2f2f093e..9b7a40ed1 100644 --- a/src/core/system_parameters/galileo_almanac_helper.cc +++ b/src/core/system_parameters/galileo_almanac_helper.cc @@ -19,6 +19,7 @@ Galileo_Almanac Galileo_Almanac_Helper::get_almanac(int i) const { Galileo_Almanac galileo_almanac; + const double sqrtAnominal = 5440.588203494; // square root of Galileo nominal orbit semi-major axis switch (i) { case 1: @@ -29,7 +30,7 @@ Galileo_Almanac Galileo_Almanac_Helper::get_almanac(int i) const galileo_almanac.delta_i = this->delta_i_7; galileo_almanac.M_0 = this->M0_7; galileo_almanac.ecc = this->e_7; - galileo_almanac.delta_sqrtA = this->DELTA_A_7; + galileo_almanac.sqrtA = sqrtAnominal + this->DELTA_A_7; galileo_almanac.OMEGA_0 = this->Omega0_7; galileo_almanac.omega = this->omega_7; galileo_almanac.OMEGAdot = this->Omega_dot_7; @@ -48,7 +49,7 @@ Galileo_Almanac Galileo_Almanac_Helper::get_almanac(int i) const galileo_almanac.delta_i = this->delta_i_8; galileo_almanac.M_0 = this->M0_9; galileo_almanac.ecc = this->e_8; - galileo_almanac.delta_sqrtA = this->DELTA_A_8; + galileo_almanac.sqrtA = sqrtAnominal + this->DELTA_A_8; galileo_almanac.OMEGA_0 = this->Omega0_8; galileo_almanac.omega = this->omega_8; galileo_almanac.OMEGAdot = this->Omega_dot_8; @@ -66,7 +67,7 @@ Galileo_Almanac Galileo_Almanac_Helper::get_almanac(int i) const galileo_almanac.delta_i = this->delta_i_9; galileo_almanac.M_0 = this->M0_10; galileo_almanac.ecc = this->e_9; - galileo_almanac.delta_sqrtA = this->DELTA_A_9; + galileo_almanac.sqrtA = sqrtAnominal + this->DELTA_A_9; galileo_almanac.OMEGA_0 = this->Omega0_10; galileo_almanac.omega = this->omega_9; galileo_almanac.OMEGAdot = this->Omega_dot_10; diff --git a/src/core/system_parameters/gnss_almanac.h b/src/core/system_parameters/gnss_almanac.h new file mode 100644 index 000000000..2206f4acc --- /dev/null +++ b/src/core/system_parameters/gnss_almanac.h @@ -0,0 +1,57 @@ +/*! + * \file gnss_almanac.h + * \brief Base class for GNSS almanac storage + * \author Carles Fernandez, 2021. cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GNSS_ALMANAC_H +#define GNSS_SDR_GNSS_ALMANAC_H + +#include <cstdint> + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + + +/*! + * \brief Base class for GNSS almanac storage + */ +class Gnss_Almanac +{ +public: + /*! + * Default constructor + */ + Gnss_Almanac() = default; + + uint32_t PRN{}; //!< SV PRN NUMBER + double delta_i{}; //!< Inclination Angle at Reference Time (relative to i_0 = 0.30 semi-circles) + int32_t toa{}; //!< Almanac data reference time of week [s] + int32_t WNa{}; //!< Almanac week number + double M_0{}; //!< Mean Anomaly at Reference Time [semi-circles] + double ecc{}; //!< Eccentricity [dimensionless] + double sqrtA{}; //!< Square Root of the Semi-Major Axis [sqrt(m)] + double OMEGA_0{}; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] + double omega{}; //!< Argument of Perigee [semi-cicles] + double OMEGAdot{}; //!< Rate of Right Ascension [semi-circles/s] + double af0{}; //!< Coefficient 0 of code phase offset model [s] + double af1{}; //!< Coefficient 1 of code phase offset model [s/s] +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GNSS_ALMANAC_H diff --git a/src/core/system_parameters/gnss_ephemeris.cc b/src/core/system_parameters/gnss_ephemeris.cc index a8698ed43..101fbf63c 100644 --- a/src/core/system_parameters/gnss_ephemeris.cc +++ b/src/core/system_parameters/gnss_ephemeris.cc @@ -184,7 +184,7 @@ double Gnss_Ephemeris::sv_clock_relativistic_term(double transmitTime) const { n0 = sqrt(GALILEO_GM / (a * a * a)); } - if (this->System == 'E') + else if (this->System == 'E') { n0 = sqrt(BEIDOU_GM / (a * a * a)); } @@ -225,7 +225,7 @@ double Gnss_Ephemeris::sv_clock_relativistic_term(double transmitTime) const { dtr_ = GALILEO_F * this->ecc * this->sqrtA * sek; } - if (this->System == 'B') + else if (this->System == 'B') { dtr_ = BEIDOU_F * this->ecc * this->sqrtA * sek; } diff --git a/src/core/system_parameters/gps_almanac.h b/src/core/system_parameters/gps_almanac.h index 2a513b588..63511656d 100644 --- a/src/core/system_parameters/gps_almanac.h +++ b/src/core/system_parameters/gps_almanac.h @@ -18,8 +18,8 @@ #ifndef GNSS_SDR_GPS_ALMANAC_H #define GNSS_SDR_GPS_ALMANAC_H +#include "gnss_almanac.h" #include <boost/serialization/nvp.hpp> -#include <cstdint> /** \addtogroup Core * \{ */ @@ -32,7 +32,7 @@ * * See https://www.gps.gov/technical/icwg/IS-GPS-200L.pdf Appendix II */ -class Gps_Almanac +class Gps_Almanac : public Gnss_Almanac { public: /*! @@ -40,20 +40,8 @@ public: */ Gps_Almanac() = default; - uint32_t PRN{}; //!< SV PRN NUMBER - double delta_i{}; //!< Inclination Angle at Reference Time (relative to i_0 = 0.30 semi-circles) - int32_t toa{}; //!< Almanac data reference time of week (Ref. 20.3.3.4.3 IS-GPS-200L) [s] - int32_t WNa{}; //!< Almanac week number - double M_0{}; //!< Mean Anomaly at Reference Time [semi-circles] - double ecc{}; //!< Eccentricity [dimensionless] - double sqrtA{}; //!< Square Root of the Semi-Major Axis [sqrt(m)] - double OMEGA_0{}; //!< Longitude of Ascending Node of Orbit Plane at Weekly Epoch [semi-circles] - double omega{}; //!< Argument of Perigee [semi-cicles] - double OMEGAdot{}; //!< Rate of Right Ascension [semi-circles/s] int32_t SV_health{}; //!< SV Health int32_t AS_status{}; //!< Anti-Spoofing Flags and SV Configuration - double af0{}; //!< Coefficient 0 of code phase offset model [s] - double af1{}; //!< Coefficient 1 of code phase offset model [s/s] template <class Archive> @@ -72,10 +60,10 @@ public: ar& BOOST_SERIALIZATION_NVP(OMEGA_0); ar& BOOST_SERIALIZATION_NVP(omega); ar& BOOST_SERIALIZATION_NVP(OMEGAdot); - ar& BOOST_SERIALIZATION_NVP(SV_health); - ar& BOOST_SERIALIZATION_NVP(AS_status); ar& BOOST_SERIALIZATION_NVP(af0); ar& BOOST_SERIALIZATION_NVP(af1); + ar& BOOST_SERIALIZATION_NVP(SV_health); + ar& BOOST_SERIALIZATION_NVP(AS_status); } }; diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 17bf694c8..8201dfdd6 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -136,7 +136,7 @@ DECLARE_string(log_dir); // #include "unit-tests/signal-processing-blocks/acquisition/beidou_b3i_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc" -#include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc" +// #include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc index 821eefadc..8cd656409 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc @@ -1,6 +1,6 @@ /*! * \file galileo_e1_pcps_acquisition_test_fpga.cc - * \brief This class implements an acquisition test Galileo FPFA acquisition + * \brief This class implements an acquisition test Galileo FPGA acquisition * \authors <ul> * <li> Marc Majoral, 2019. mmajoral(at)cttc.cat * <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc index caa1aad58..5cfca59d5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc @@ -1,7 +1,7 @@ /*! * \file serdes_monitor_pvt_test.cc * \brief Implements Unit Test for the serdes_monitor_pvt class. - * \author Carles Fernandez_prades, 2019. cfernandez(at)cttc.es + * \author Carles Fernandez-Prades, 2019. cfernandez(at)cttc.es * * ----------------------------------------------------------------------------- * @@ -20,7 +20,7 @@ TEST(Serdes_Monitor_Pvt_Test, Simpletest) { - std::shared_ptr<Monitor_Pvt> monitor = std::make_shared<Monitor_Pvt>(Monitor_Pvt()); + auto monitor = std::make_shared<Monitor_Pvt>(Monitor_Pvt()); double true_latitude = 23.4; monitor->latitude = true_latitude; @@ -29,13 +29,35 @@ TEST(Serdes_Monitor_Pvt_Test, Simpletest) gnss_sdr::MonitorPvt mon; mon.ParseFromString(serialized_data); - - serdes.readProtobuffer(mon); - - gnss_sdr::GalileoEphemeris ephgal; - Serdes_Galileo_Eph gal_serdes = Serdes_Galileo_Eph(); - gal_serdes.readProtobuffer(ephgal); - double read_latitude = mon.latitude(); EXPECT_NEAR(true_latitude, read_latitude, 0.000001); } + + +TEST(Serdes_Monitor_Pvt_Test, GalileoEphemerisSerdes) +{ + auto eph = std::make_shared<Galileo_Ephemeris>(); + int true_tow = 12345; + eph->tow = true_tow; + + Serdes_Galileo_Eph gal_serdes = Serdes_Galileo_Eph(); + std::string serialized_data = gal_serdes.createProtobuffer(eph); + + gnss_sdr::GalileoEphemeris ephgal; + ephgal.ParseFromString(serialized_data); + + double true_delta_n = 0.33; + ephgal.set_delta_n(true_delta_n); + + int read_tow = ephgal.tow(); + EXPECT_EQ(true_tow, read_tow); + + double read_delta_n = ephgal.delta_n(); + EXPECT_NEAR(true_delta_n, read_delta_n, 0.000001); + + auto eph2 = gal_serdes.readProtobuffer(ephgal); + double read2_delta_n = eph2.delta_n; + int read2_tow = eph2.tow; + EXPECT_EQ(true_tow, read2_tow); + EXPECT_NEAR(true_delta_n, read2_delta_n, 0.000001); +}