mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-29 06:27:44 +00:00 
			
		
		
		
	Merge branch 'feature/signal_source_interface' of https://github.com/jwmelto/gnss-sdr into jwmelto-feature/signal_source_interface
This commit is contained in:
		| @@ -36,6 +36,9 @@ SPDX-FileCopyrightText: 2011-2021 Carles Fernandez-Prades <carles.fernandez@cttc | ||||
|   asking them to sign the CLA document). | ||||
| - Improved handling of change in GNU Radio 3.9 FFT API. | ||||
| - Improved handling of the filesystem library. | ||||
| - Added an abstract class `SignalSourceInterface` and a common base class | ||||
|   `SignalSourceBase`, which allow to remove a lot of duplicated code in Signal | ||||
|   Source blocks, and further abstract file-based interfaces behind them. | ||||
| - Do not apply clang-tidy fixes to protobuf-generated headers. | ||||
| - Refactored private implementation of flow graph connection and disconnection | ||||
|   for improved source code readability. | ||||
|   | ||||
| @@ -31,6 +31,7 @@ set(GNSS_SPLIBS_SOURCES | ||||
|     item_type_helpers.cc | ||||
|     pass_through.cc | ||||
|     short_x2_to_cshort.cc | ||||
|     gnss_sdr_string_literals.cc | ||||
| ) | ||||
|  | ||||
| set(GNSS_SPLIBS_HEADERS | ||||
| @@ -61,6 +62,7 @@ set(GNSS_SPLIBS_HEADERS | ||||
|     item_type_helpers.h | ||||
|     pass_through.h | ||||
|     short_x2_to_cshort.h | ||||
|     gnss_sdr_string_literals.h | ||||
| ) | ||||
|  | ||||
| if(ENABLE_OPENCL) | ||||
|   | ||||
							
								
								
									
										37
									
								
								src/algorithms/libs/gnss_sdr_string_literals.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/algorithms/libs/gnss_sdr_string_literals.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /*! | ||||
|  * \file gnss_sdr_string_literals.cc | ||||
|  * \brief This file implements the ""s operator for std::string in C++11, and | ||||
|  * puts it into the std::string_literals namespace. This is already implemented | ||||
|  * in C++14, so this is only compiled when using C++11. The .cc file is required | ||||
|  * for avoiding the duplication of symbols. | ||||
|  * | ||||
|  * \author Carles Fernandez-Prades, 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 | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "gnss_sdr_string_literals.h" | ||||
|  | ||||
| #if __cplusplus == 201103L | ||||
|  | ||||
| namespace std | ||||
| { | ||||
| namespace string_literals | ||||
| { | ||||
| std::string operator"" s(const char* str, std::size_t len) | ||||
| { | ||||
|     return std::string(str, len); | ||||
| }; | ||||
| }  // namespace string_literals | ||||
| }  // namespace std | ||||
|  | ||||
| #endif  // __cplusplus == 201103L | ||||
							
								
								
									
										48
									
								
								src/algorithms/libs/gnss_sdr_string_literals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/algorithms/libs/gnss_sdr_string_literals.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| /*! | ||||
|  * \file gnss_sdr_string_literals.h | ||||
|  * \brief This file implements the ""s operator for std::string in C++11, and | ||||
|  * puts it into the std::string_literals namespace. This is already implemented | ||||
|  * in C++14, so this is only compiled when using C++11. The .cc file is required | ||||
|  * for avoiding the duplication of symbols. | ||||
|  * | ||||
|  * \author Carles Fernandez-Prades, 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_STRING_LITERALS_H | ||||
| #define GNSS_SDR_STRING_LITERALS_H | ||||
|  | ||||
| /** \addtogroup Algorithms_Library | ||||
|  * \{ */ | ||||
| /** \addtogroup Algorithm_libs algorithms_libs | ||||
|  * \{ */ | ||||
|  | ||||
| #if __cplusplus == 201103L | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
|  | ||||
| namespace std | ||||
| { | ||||
| namespace string_literals | ||||
| { | ||||
| std::string operator"" s(const char* str, std::size_t len); | ||||
| }  // namespace string_literals | ||||
| }  // namespace std | ||||
|  | ||||
| #endif  // __cplusplus == 201103L | ||||
|  | ||||
| /** \} */ | ||||
| /** \} */ | ||||
|  | ||||
| #endif  // GNSS_SDR_STRING_LITERALS_H | ||||
| @@ -92,6 +92,8 @@ endif() | ||||
|  | ||||
|  | ||||
| set(SIGNAL_SOURCE_ADAPTER_SOURCES | ||||
|     signal_source_base.cc | ||||
|     file_source_base.cc | ||||
|     file_signal_source.cc | ||||
|     multichannel_file_signal_source.cc | ||||
|     gen_signal_source.cc | ||||
| @@ -106,6 +108,8 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES | ||||
| ) | ||||
|  | ||||
| set(SIGNAL_SOURCE_ADAPTER_HEADERS | ||||
|     signal_source_base.h | ||||
|     file_source_base.h | ||||
|     file_signal_source.h | ||||
|     multichannel_file_signal_source.h | ||||
|     gen_signal_source.h | ||||
| @@ -156,6 +160,7 @@ target_link_libraries(signal_source_adapters | ||||
|         Gnuradio::blocks | ||||
|         signal_source_gr_blocks | ||||
|     PRIVATE | ||||
|         algorithms_libs | ||||
|         gnss_sdr_flags | ||||
|         core_system_parameters | ||||
|         Glog::glog | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| #include "ad9361_manager.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "uio_fpga.h" | ||||
| #include <glog/logging.h> | ||||
| #include <iio.h> | ||||
| @@ -42,9 +43,12 @@ | ||||
| #include <vector> | ||||
|  | ||||
|  | ||||
| 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))) : role_(role), in_stream_(in_stream), out_stream_(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) | ||||
| { | ||||
|     const std::string default_gain_mode("slow_attack"); | ||||
|     const double default_tx_attenuation_db = -10.0; | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| #include "fpga_dynamic_bit_selection.h" | ||||
| #include "fpga_switch.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| @@ -39,7 +40,7 @@ | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| class Ad9361FpgaSignalSource : public GNSSBlockInterface | ||||
| class Ad9361FpgaSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, | ||||
| @@ -50,19 +51,6 @@ public: | ||||
|  | ||||
|     void start() override; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Ad9361_Fpga_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Ad9361_Fpga_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -100,8 +88,6 @@ private: | ||||
|     std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; | ||||
|     std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; | ||||
|  | ||||
|     std::string role_; | ||||
|  | ||||
|     // Front-end settings | ||||
|     std::string gain_mode_rx1_; | ||||
|     std::string gain_mode_rx2_; | ||||
|   | ||||
| @@ -17,13 +17,17 @@ | ||||
|  | ||||
| #include "custom_udp_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <iostream> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| CustomUDPSignalSource::CustomUDPSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused))) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused))) | ||||
|     : SignalSourceBase(configuration, role, "Custom_UDP_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     // DUMP PARAMETERS | ||||
|     const std::string default_dump_file("./data/signal_source.dat"); | ||||
|   | ||||
| @@ -19,8 +19,8 @@ | ||||
| #define GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "gr_complex_ip_packet_source.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/null_sink.h> | ||||
| #include <pmt/pmt.h> | ||||
| @@ -40,7 +40,7 @@ class ConfigurationInterface; | ||||
|  * \brief This class reads from UDP packets, which streams interleaved | ||||
|  * I/Q samples over a network. | ||||
|  */ | ||||
| class CustomUDPSignalSource : public GNSSBlockInterface | ||||
| class CustomUDPSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     CustomUDPSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -49,19 +49,6 @@ public: | ||||
|  | ||||
|     ~CustomUDPSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Custom_UDP_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Custom_UDP_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -78,7 +65,6 @@ private: | ||||
|     std::vector<gnss_shared_ptr<gr::block>> null_sinks_; | ||||
|     std::vector<gnss_shared_ptr<gr::block>> file_sink_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|  | ||||
|   | ||||
| @@ -10,343 +10,29 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| #include <iomanip> | ||||
| #include <iostream>  // for std::cerr | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| FileSignalSource::FileSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
| FileSignalSource::FileSignalSource(ConfigurationInterface const* configuration, | ||||
|     std::string const& role, unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : FileSourceBase(configuration, role, "File_Signal_Source"s, queue, "short"s) | ||||
| { | ||||
|     const std::string default_filename("./example_capture.dat"); | ||||
|     const std::string default_item_type("short"); | ||||
|     const std::string default_dump_filename("./my_capture.dat"); | ||||
|  | ||||
|     const double default_seconds_to_skip = 0.0; | ||||
|  | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     filename_ = configuration->property(role + ".filename", default_filename); | ||||
|  | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
|  | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|     repeat_ = configuration->property(role + ".repeat", false); | ||||
|     dump_ = configuration->property(role + ".dump", false); | ||||
|     dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); | ||||
|     enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); | ||||
|  | ||||
|     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); | ||||
|     int64_t samples_to_skip = 0; | ||||
|  | ||||
|     bool is_complex = false; | ||||
|  | ||||
|     if (item_type_ == "gr_complex") | ||||
|         { | ||||
|             item_size_ = sizeof(gr_complex); | ||||
|         } | ||||
|     else if (item_type_ == "float") | ||||
|         { | ||||
|             item_size_ = sizeof(float); | ||||
|         } | ||||
|     else if (item_type_ == "short") | ||||
|         { | ||||
|             item_size_ = sizeof(int16_t); | ||||
|         } | ||||
|     else if (item_type_ == "ishort") | ||||
|         { | ||||
|             item_size_ = sizeof(int16_t); | ||||
|             is_complex = true; | ||||
|         } | ||||
|     else if (item_type_ == "byte") | ||||
|         { | ||||
|             item_size_ = sizeof(int8_t); | ||||
|         } | ||||
|     else if (item_type_ == "ibyte") | ||||
|         { | ||||
|             item_size_ = sizeof(int8_t); | ||||
|             is_complex = true; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ | ||||
|                          << " unrecognized item type. Using gr_complex."; | ||||
|             item_size_ = sizeof(gr_complex); | ||||
|         } | ||||
|     try | ||||
|         { | ||||
|             file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); | ||||
|  | ||||
|             if (seconds_to_skip > 0) | ||||
|                 { | ||||
|                     samples_to_skip = static_cast<int64_t>(seconds_to_skip * sampling_frequency_); | ||||
|  | ||||
|                     if (is_complex) | ||||
|                         { | ||||
|                             samples_to_skip *= 2; | ||||
|                         } | ||||
|                 } | ||||
|             if (header_size > 0) | ||||
|                 { | ||||
|                     samples_to_skip += header_size; | ||||
|                 } | ||||
|  | ||||
|             if (samples_to_skip > 0) | ||||
|                 { | ||||
|                     LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file"; | ||||
|                     if (not file_source_->seek(samples_to_skip, SEEK_SET)) | ||||
|                         { | ||||
|                             LOG(INFO) << "Error skipping bytes!"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             if (filename_ == default_filename) | ||||
|                 { | ||||
|                     std::cerr | ||||
|                         << "The configuration file has not been found.\n" | ||||
|                         << "Please create a configuration file based on the examples at the 'conf/' folder\n" | ||||
|                         << "and then generate your own GNSS Software Defined Receiver by doing:\n" | ||||
|                         << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n"; | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     std::cerr | ||||
|                         << "The receiver was configured to work with a file signal source\n" | ||||
|                         << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                         << "Please modify your configuration file\n" | ||||
|                         << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                         << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                         << "Examples of configuration files available at:\n" | ||||
|                         << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n"; | ||||
|                 } | ||||
|  | ||||
|             LOG(INFO) << "file_signal_source: Unable to open the samples file " | ||||
|                       << filename_.c_str() << ", exiting the program."; | ||||
|             throw(e); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     if (samples_ == 0)  // read all file | ||||
|         { | ||||
|             /*! | ||||
|              * 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(filename_.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::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << '\n'; | ||||
|                     LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); | ||||
|                 } | ||||
|             std::streamsize ss = std::cout.precision(); | ||||
|             std::cout << std::setprecision(16); | ||||
|             std::cout << "Processing file " << filename_ << ", 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>(sampling_frequency_)));  // process all the samples available in the file excluding at least the last 1 ms | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||
|     double signal_duration_s = static_cast<double>(samples_) * (1 / static_cast<double>(sampling_frequency_)); | ||||
|  | ||||
|     if (is_complex) | ||||
|         { | ||||
|             signal_duration_s /= 2.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"; | ||||
|  | ||||
|     valve_ = gnss_sdr_make_valve(item_size_, samples_, queue); | ||||
|     DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|     if (dump_) | ||||
|         { | ||||
|             sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|         } | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             throttle_ = gr::blocks::throttle::make(item_size_, sampling_frequency_); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|     if (in_streams_ > 0) | ||||
|     if (in_streams > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "A signal source does not have an input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 1) | ||||
|     if (out_streams > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void FileSignalSource::connect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     top_block->connect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected file source to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(file_source_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(file_source_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void FileSignalSource::disconnect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to throttle"; | ||||
|                     top_block->disconnect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(file_source_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(file_source_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr FileSignalSource::get_left_block() | ||||
| { | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     return gr::blocks::file_source::sptr(); | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr FileSignalSource::get_right_block() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             return valve_; | ||||
|         } | ||||
|     if (enable_throttle_control_ == true) | ||||
|         { | ||||
|             return throttle_; | ||||
|         } | ||||
|     return file_source_; | ||||
| } | ||||
|   | ||||
| @@ -21,15 +21,7 @@ | ||||
| #ifndef GNSS_SDR_FILE_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
| #include "file_source_base.h" | ||||
|  | ||||
| /** \addtogroup Signal_Source Signal Source | ||||
|  * Classes for Signal Source management. | ||||
| @@ -45,84 +37,16 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class FileSignalSource : public GNSSBlockInterface | ||||
| class FileSignalSource : public FileSourceBase | ||||
| { | ||||
| public: | ||||
|     FileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
|     FileSignalSource(ConfigurationInterface const* configuration, std::string const& role, | ||||
|         unsigned int in_streams, unsigned int out_streams, | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue); | ||||
|  | ||||
|     ~FileSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     inline std::string filename() const | ||||
|     { | ||||
|         return filename_; | ||||
|     } | ||||
|  | ||||
|     inline std::string item_type() const | ||||
|     { | ||||
|         return item_type_; | ||||
|     } | ||||
|  | ||||
|     inline bool repeat() const | ||||
|     { | ||||
|         return repeat_; | ||||
|     } | ||||
|  | ||||
|     inline int64_t sampling_frequency() const | ||||
|     { | ||||
|         return sampling_frequency_; | ||||
|     } | ||||
|  | ||||
|     inline uint64_t samples() const | ||||
|     { | ||||
|         return samples_; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string filename_; | ||||
|     std::string dump_filename_; | ||||
|  | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     size_t item_size_; | ||||
|  | ||||
|     uint32_t in_streams_; | ||||
|     uint32_t out_streams_; | ||||
|  | ||||
|     bool enable_throttle_control_; | ||||
|     bool repeat_; | ||||
|     bool dump_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										506
									
								
								src/algorithms/signal_source/adapters/file_source_base.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										506
									
								
								src/algorithms/signal_source/adapters/file_source_base.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,506 @@ | ||||
| /*! | ||||
|  * \file file_source_base.cc | ||||
|  * \brief Implementation of the base class for file-oriented signal_source GNSS blocks | ||||
|  * \author Jim Melton, 2021. jim.melton(at)sncorp.com | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "file_source_base.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_filesystem.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <cmath>  // ceil, floor | ||||
| #include <fstream> | ||||
| #include <utility>  // move | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std::string const& role, std::string impl, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue, | ||||
|     std::string default_item_type) | ||||
|     : SignalSourceBase(configuration, role, std::move(impl)), filename_(configuration->property(role + ".filename"s, "../data/example_capture.dat"s)), | ||||
|  | ||||
|       file_source_(),  // NOLINT | ||||
|  | ||||
|       item_type_(configuration->property(role + ".item_type"s, default_item_type)),  // NOLINT | ||||
|       item_size_(0), | ||||
|       is_complex_(false), | ||||
|  | ||||
|       // apparently, MacOS (LLVM) finds 0UL ambiguous with bool, int64_t, uint64_t, int32_t, int16_t, uint16_t,... float, double | ||||
|       header_size_(configuration->property(role + ".header_size"s, uint64_t(0))), | ||||
|       seconds_to_skip_(configuration->property(role + ".seconds_to_skip"s, 0.0)), | ||||
|       repeat_(configuration->property(role + ".repeat"s, false)), | ||||
|  | ||||
|       samples_(configuration->property(role + ".samples"s, uint64_t(0))), | ||||
|       sampling_frequency_(configuration->property(role + ".sampling_frequency"s, int64_t(0))), | ||||
|       valve_(),  // NOLINT | ||||
|       queue_(queue), | ||||
|  | ||||
|       enable_throttle_control_(configuration->property(role + ".enable_throttle_control"s, false)), | ||||
|       throttle_(),  // NOLINT | ||||
|  | ||||
|       dump_(configuration->property(role + ".dump"s, false)), | ||||
|       dump_filename_(configuration->property(role + ".dump_filename"s, "../data/my_capture.dat"s)), | ||||
|       sink_()  // NOLINT | ||||
| { | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void FileSourceBase::init() | ||||
| { | ||||
|     create_file_source(); | ||||
|  | ||||
|     // At this point, we know that the file exists | ||||
|     samples_ = computeSamplesInFile(); | ||||
|     auto signal_duration_s = 1.0 * samples_ / sampling_frequency_; | ||||
|  | ||||
|     if (is_complex()) | ||||
|         { | ||||
|             signal_duration_s /= 2.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"; | ||||
|  | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|  | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|  | ||||
|     create_throttle(); | ||||
|     create_valve(); | ||||
|     create_sink(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void FileSourceBase::connect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     init(); | ||||
|     pre_connect_hook(top_block); | ||||
|  | ||||
|     auto input = gr::basic_block_sptr(); | ||||
|     auto output = gr::basic_block_sptr(); | ||||
|  | ||||
|     // THROTTLE | ||||
|     if (throttle()) | ||||
|         { | ||||
|             // if we are throttling... | ||||
|             top_block->connect(source(), 0, throttle(), 0); | ||||
|             DLOG(INFO) << "connected file source to throttle"; | ||||
|  | ||||
|             input = throttle(); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             // no throttle; let 'er rip | ||||
|             input = source(); | ||||
|         } | ||||
|  | ||||
|     // VALVE | ||||
|     if (valve()) | ||||
|         { | ||||
|             top_block->connect(input, 0, valve(), 0); | ||||
|             DLOG(INFO) << "connected source to valve"; | ||||
|  | ||||
|             output = valve(); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             // TODO: dumping a file source is unlikely, but should this be the raw file source or the | ||||
|             // throttle if there is one?  I'm leaning towards "output=input" | ||||
|             output = source();  // output = input; | ||||
|         } | ||||
|  | ||||
|     // DUMP | ||||
|     if (sink()) | ||||
|         { | ||||
|             top_block->connect(output, 0, sink(), 0); | ||||
|             DLOG(INFO) << "connected output to file sink"; | ||||
|         } | ||||
|  | ||||
|     post_connect_hook(top_block); | ||||
| } | ||||
|  | ||||
|  | ||||
| void FileSourceBase::disconnect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     auto input = gr::basic_block_sptr(); | ||||
|     auto output = gr::basic_block_sptr(); | ||||
|  | ||||
|     pre_disconnect_hook(top_block); | ||||
|  | ||||
|     // THROTTLE | ||||
|     if (throttle()) | ||||
|         { | ||||
|             // if we are throttling... | ||||
|             top_block->disconnect(source(), 0, throttle(), 0); | ||||
|             DLOG(INFO) << "disconnected file source from throttle"; | ||||
|  | ||||
|             input = throttle(); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             // no throttle; let 'er rip | ||||
|             input = source(); | ||||
|         } | ||||
|  | ||||
|     // VALVE | ||||
|     if (valve()) | ||||
|         { | ||||
|             top_block->disconnect(input, 0, valve(), 0); | ||||
|             DLOG(INFO) << "disconnected source to valve"; | ||||
|  | ||||
|             output = valve(); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             // TODO: dumping a file source is unlikely, but should this be the raw file source or the | ||||
|             // throttle if there is one?  I'm leaning towards "output=input" | ||||
|             output = source();  // output = input; | ||||
|         } | ||||
|  | ||||
|     // DUMP | ||||
|     if (sink()) | ||||
|         { | ||||
|             top_block->disconnect(output, 0, sink(), 0); | ||||
|             DLOG(INFO) << "disconnected output to file sink"; | ||||
|         } | ||||
|  | ||||
|     post_disconnect_hook(top_block); | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr FileSourceBase::get_left_block() | ||||
| { | ||||
|     // TODO: is this right? Shouldn't the left block be a nullptr? | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     return gr::blocks::file_source::sptr(); | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr FileSourceBase::get_right_block() | ||||
| { | ||||
|     // clang-tidy wants braces around the if-conditions. clang-format wants to break the braces into | ||||
|     // multiple line blocks. It's much more readable this way | ||||
|     // clang-format off | ||||
|     if (valve_) { return valve_; } | ||||
|     if (throttle_) { return throttle_; } | ||||
|     return source(); | ||||
|     // clang-format on | ||||
| } | ||||
|  | ||||
|  | ||||
| std::string FileSourceBase::filename() const | ||||
| { | ||||
|     return filename_; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::string FileSourceBase::item_type() const | ||||
| { | ||||
|     return item_type_; | ||||
| } | ||||
|  | ||||
|  | ||||
| size_t FileSourceBase::item_size() | ||||
| { | ||||
|     return item_size_; | ||||
| } | ||||
|  | ||||
|  | ||||
| size_t FileSourceBase::item_size() const | ||||
| { | ||||
|     return item_size_; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool FileSourceBase::repeat() const | ||||
| { | ||||
|     return repeat_; | ||||
| } | ||||
|  | ||||
|  | ||||
| int64_t FileSourceBase::sampling_frequency() const | ||||
| { | ||||
|     return sampling_frequency_; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint64_t FileSourceBase::samples() const | ||||
| { | ||||
|     return samples_; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::tuple<size_t, bool> FileSourceBase::itemTypeToSize() | ||||
| { | ||||
|     auto is_complex_t = false; | ||||
|     auto item_size = size_t(0); | ||||
|  | ||||
|     if (item_type_ == "gr_complex") | ||||
|         { | ||||
|             item_size = sizeof(gr_complex); | ||||
|         } | ||||
|     else if (item_type_ == "float") | ||||
|         { | ||||
|             item_size = sizeof(float); | ||||
|         } | ||||
|     else if (item_type_ == "short") | ||||
|         { | ||||
|             item_size = sizeof(int16_t); | ||||
|         } | ||||
|     else if (item_type_ == "ishort") | ||||
|         { | ||||
|             item_size = sizeof(int16_t); | ||||
|             is_complex_t = true; | ||||
|         } | ||||
|     else if (item_type_ == "byte") | ||||
|         { | ||||
|             item_size = sizeof(int8_t); | ||||
|         } | ||||
|     else if (item_type_ == "ibyte") | ||||
|         { | ||||
|             item_size = sizeof(int8_t); | ||||
|             is_complex_t = true; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ | ||||
|                          << " unrecognized item type. Using gr_complex."; | ||||
|             item_size = sizeof(gr_complex); | ||||
|         } | ||||
|  | ||||
|     return std::make_tuple(item_size, is_complex_t); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Default case is one decoded packet per one read sample | ||||
| double FileSourceBase::packetsPerSample() const { return 1.0; } | ||||
|  | ||||
|  | ||||
| size_t FileSourceBase::samplesToSkip() const | ||||
| { | ||||
|     auto samples_to_skip = size_t(0); | ||||
|  | ||||
|     if (seconds_to_skip_ > 0) | ||||
|         { | ||||
|             // sampling_frequency is in terms of actual samples (output packets). If this source is | ||||
|             // compressed, there may be multiple packets per file (read) sample. First compute the | ||||
|             // actual number of samples to skip (function of time and sample rate) | ||||
|             samples_to_skip = static_cast<size_t>(seconds_to_skip_ * sampling_frequency_); | ||||
|  | ||||
|             // convert from sample to input items, scaling this value to input item space | ||||
|             // (rounding up) | ||||
|             samples_to_skip = std::ceil(samples_to_skip / packetsPerSample()); | ||||
|  | ||||
|             // complex inputs require two input items for one sample (arguably, packetsPerSample could be scaled by 0.5) | ||||
|             if (is_complex()) | ||||
|                 { | ||||
|                     samples_to_skip *= 2; | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     if (header_size_ > 0) | ||||
|         { | ||||
|             samples_to_skip += header_size_; | ||||
|         } | ||||
|  | ||||
|     return samples_to_skip; | ||||
| } | ||||
|  | ||||
|  | ||||
| size_t FileSourceBase::computeSamplesInFile() const | ||||
| { | ||||
|     auto n_samples = size_t(samples()); | ||||
|  | ||||
|     // if configured with 0 samples (read the whole file), figure out how many samples are in the file, and go from there | ||||
|     if (n_samples == 0) | ||||
|         { | ||||
|             // this could throw, but the existence of the file has been proven before we get here. | ||||
|             auto size = fs::file_size(filename()); | ||||
|  | ||||
|             // if there is some kind of compression/encoding, figure out the uncompressed number of samples | ||||
|             n_samples = std::floor(packetsPerSample() * size / item_size()); | ||||
|  | ||||
|             auto to_skip = samplesToSkip(); | ||||
|  | ||||
|             /*! | ||||
| 	     * 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 at least | ||||
| 	     * the last 2 milliseconds, and enable always the valve block | ||||
| 	     */ | ||||
|             auto tail = static_cast<size_t>(std::ceil(0.002 * sampling_frequency())); | ||||
|  | ||||
|             DLOG(INFO) << "Total samples in the file= " << n_samples; | ||||
|             std::cout << "Processing file " << filename() << ", which contains " << n_samples << " samples (" << size << " bytes)\n"; | ||||
|  | ||||
|             if (n_samples > (to_skip + tail)) | ||||
|                 { | ||||
|                     // process all the samples available in the file excluding up to the last 2 ms | ||||
|                     n_samples -= to_skip + tail; | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     // this will terminate the program | ||||
|                     LOG(FATAL) << "Skipping " << to_skip << " samples from the front and truncating 2ms (" << tail << " samples)\n" | ||||
|                                << "is greater than the number of samples in the file (" << n_samples << ")"; | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     return n_samples; | ||||
| } | ||||
|  | ||||
|  | ||||
| size_t FileSourceBase::source_item_size() const | ||||
| { | ||||
|     // delegate the size of the source to the source() object, so sub-classes have less work to do | ||||
|     DLOG(INFO) << "source_item_size is " << source()->output_signature()->sizeof_stream_item(0); | ||||
|     return source()->output_signature()->sizeof_stream_item(0); | ||||
| } | ||||
|  | ||||
|  | ||||
| bool FileSourceBase::is_complex() const { return is_complex_; } | ||||
|  | ||||
|  | ||||
| // Simple accessors | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::source() const { return file_source(); } | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::file_source() const { return file_source_; } | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::valve() const { return valve_; } | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::throttle() const { return throttle_; } | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::sink() const { return sink_; } | ||||
|  | ||||
|  | ||||
| gr::blocks::file_source::sptr FileSourceBase::create_file_source() | ||||
| { | ||||
|     auto item_tuple = itemTypeToSize(); | ||||
|     item_size_ = std::get<0>(item_tuple); | ||||
|     is_complex_ = std::get<1>(item_tuple); | ||||
|  | ||||
|     try | ||||
|         { | ||||
|             // TODO: why are we manually seeking, instead of passing the samples_to_skip to the file_source factory? | ||||
|             auto samples_to_skip = samplesToSkip(); | ||||
|  | ||||
|             file_source_ = gr::blocks::file_source::make(item_size(), filename().data(), repeat()); | ||||
|  | ||||
|             if (samples_to_skip > 0) | ||||
|                 { | ||||
|                     LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file"; | ||||
|                     if (not file_source_->seek(samples_to_skip, SEEK_SET)) | ||||
|                         { | ||||
|                             LOG(ERROR) << "Error skipping bytes!"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             std::cerr | ||||
|                 << "The receiver was configured to work with a file-based signal source\n" | ||||
|                 << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                 << "[" << filename() << "]\n" | ||||
|                 << "\n" | ||||
|                 << "Please modify your configuration file\n" | ||||
|                 << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                 << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                 << "Examples of configuration files available at:\n" | ||||
|                 << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n" | ||||
|                 << std::endl; | ||||
|  | ||||
|             LOG(ERROR) << "file_signal_source: Unable to open the samples file " | ||||
|                        << filename() << ", exiting the program."; | ||||
|             throw; | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << implementation() << "(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     // enable subclass hooks | ||||
|     create_file_source_hook(); | ||||
|  | ||||
|     return file_source_; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::blocks::throttle::sptr FileSourceBase::create_throttle() | ||||
| { | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             // if we are throttling... | ||||
|             throttle_ = gr::blocks::throttle::make(source_item_size(), sampling_frequency()); | ||||
|             DLOG(INFO) << "throttle(" << throttle_->unique_id() << ")"; | ||||
|  | ||||
|             // enable subclass hooks | ||||
|             create_throttle_hook(); | ||||
|         } | ||||
|     return throttle_; | ||||
| } | ||||
|  | ||||
|  | ||||
| gnss_shared_ptr<gr::block> FileSourceBase::create_valve() | ||||
| { | ||||
|     if (samples() > 0) | ||||
|         { | ||||
|             // if a number of samples is specified, honor it by creating a valve | ||||
|             // In practice, this is always true | ||||
|             valve_ = gnss_sdr_make_valve(source_item_size(), samples(), queue_); | ||||
|             DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|             // enable subclass hooks | ||||
|             create_valve_hook(); | ||||
|         } | ||||
|     return valve_; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::blocks::file_sink::sptr FileSourceBase::create_sink() | ||||
| { | ||||
|     if (dump_) | ||||
|         { | ||||
|             sink_ = gr::blocks::file_sink::make(source_item_size(), dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|  | ||||
|             // enable subclass hooks | ||||
|             create_sink_hook(); | ||||
|         } | ||||
|     return sink_; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Subclass hooks to augment created objects, as required | ||||
| void FileSourceBase::create_file_source_hook() {} | ||||
| void FileSourceBase::create_throttle_hook() {} | ||||
| void FileSourceBase::create_valve_hook() {} | ||||
| void FileSourceBase::create_sink_hook() {} | ||||
|  | ||||
|  | ||||
| // Subclass hooks for connection/disconnectino | ||||
| void FileSourceBase::pre_connect_hook(gr::top_block_sptr top_block [[maybe_unused]]) {} | ||||
| void FileSourceBase::post_connect_hook(gr::top_block_sptr top_block [[maybe_unused]]) {} | ||||
| void FileSourceBase::pre_disconnect_hook(gr::top_block_sptr top_block [[maybe_unused]]) {} | ||||
| void FileSourceBase::post_disconnect_hook(gr::top_block_sptr top_block [[maybe_unused]]) {} | ||||
							
								
								
									
										186
									
								
								src/algorithms/signal_source/adapters/file_source_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								src/algorithms/signal_source/adapters/file_source_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | ||||
| /*! | ||||
|  * \file file_source_base.h | ||||
|  * \brief Header file of the base class to file-oriented signal_source GNSS blocks. | ||||
|  * \author Jim Melton, 2021. jim.melton(at)sncorp.com | ||||
|  * | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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_FILE_SOURCE_BASE_H | ||||
| #define GNSS_SDR_FILE_SOURCE_BASE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <tuple> | ||||
|  | ||||
| // for dump | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
|  | ||||
| //! \brief Base class to file-oriented SignalSourceBase GNSS blocks. | ||||
| //! | ||||
| //! This class supports the following properties: | ||||
| //! | ||||
| //!   .filename - the path to the input file | ||||
| //!             - may be overridden by the -signal_source or -s command-line arguments | ||||
| //! | ||||
| //!   .samples  - number of samples to process (default 0) | ||||
| //!             - if not specified or 0, read the entire file; otherwise stop after that many samples | ||||
| //! | ||||
| //!   .sampling_frequency - the frequency of the sampled data (samples/second) | ||||
| //! | ||||
| //!   .item_type - data type of the samples (default "short") | ||||
| //! | ||||
| //!   .header_size - the size of a prefixed header to skip in "samples" (default 0) | ||||
| //! | ||||
| //!   .seconds_to_skip - number of seconds of lead-in data to skip over (default 0) | ||||
| //! | ||||
| //!   .enable_throttle_control - whether to stop reading if the upstream buffer is full (default false) | ||||
| //! | ||||
| //!   .repeat   - whether to rewind and continue at end of file (default false) | ||||
| //! | ||||
| //! (probably abstracted to the base class) | ||||
| //! | ||||
| //!   .dump     - whether to archive input data | ||||
| //! | ||||
| //!   .dump_filename - if dumping, path to file for output | ||||
|  | ||||
|  | ||||
| class FileSourceBase : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     // Virtual overrides | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     //! The file to read | ||||
|     std::string filename() const; | ||||
|  | ||||
|     //! The item type | ||||
|     std::string item_type() const; | ||||
|  | ||||
|     //! The configured size of each item | ||||
|     size_t item_size() override; | ||||
|     virtual size_t item_size() const;  // what the interface **should** have declared | ||||
|  | ||||
|     //! Whether to repeat reading after end-of-file | ||||
|     bool repeat() const; | ||||
|  | ||||
|     //! The sampling frequency of the source file | ||||
|     int64_t sampling_frequency() const; | ||||
|  | ||||
|     //! The number of samples in the file | ||||
|     uint64_t samples() const; | ||||
|  | ||||
| protected: | ||||
|     //! \brief Constructor | ||||
|     //! | ||||
|     //! Subclasses may want to assert default item types that are appropriate to the specific file | ||||
|     //! type supported. Rather than require the item type to be specified in the config file, allow | ||||
|     //! sub-classes to impose their will | ||||
|     FileSourceBase(ConfigurationInterface const* configuration, std::string const& role, std::string impl, | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue, | ||||
|         std::string default_item_type = "short"); | ||||
|  | ||||
|     //! Perform post-construction initialization | ||||
|     void init(); | ||||
|  | ||||
|     //! Compute the item size, from the item_type(). Subclasses may constrain types that don't make | ||||
|     //  sense. The return of this method is a tuple of item_size and is_complex | ||||
|     virtual std::tuple<size_t, bool> itemTypeToSize(); | ||||
|  | ||||
|     //! The number of (possibly unpacked) samples in a (raw) file sample (default=1) | ||||
|     virtual double packetsPerSample() const; | ||||
|  | ||||
|     //! Compute the number of samples to skip | ||||
|     virtual size_t samplesToSkip() const; | ||||
|  | ||||
|     //! Compute the number of samples in the file | ||||
|     size_t computeSamplesInFile() const; | ||||
|  | ||||
|     //! Abstracted front-end source. Sub-classes may override if they create specialized chains to | ||||
|     //! decode source files into a usable format | ||||
|     virtual gnss_shared_ptr<gr::block> source() const; | ||||
|  | ||||
|     //! For complex source chains, the size of the file item may not be the same as the size of the | ||||
|     // "source" (decoded) item. This method allows subclasses to handle these differences | ||||
|     virtual size_t source_item_size() const; | ||||
|     bool is_complex() const; | ||||
|  | ||||
|     // Generic access to created objects | ||||
|     gnss_shared_ptr<gr::block> file_source() const; | ||||
|     gnss_shared_ptr<gr::block> valve() const; | ||||
|     gnss_shared_ptr<gr::block> throttle() const; | ||||
|     gnss_shared_ptr<gr::block> sink() const; | ||||
|  | ||||
|     // The methods create the various blocks, if enabled, and return access to them. The created | ||||
|     // object is also held in this class | ||||
|     gr::blocks::file_source::sptr create_file_source(); | ||||
|     gr::blocks::throttle::sptr create_throttle(); | ||||
|     gnss_shared_ptr<gr::block> create_valve(); | ||||
|     gr::blocks::file_sink::sptr create_sink(); | ||||
|  | ||||
|     // Subclass hooks to augment created objects, as required | ||||
|     virtual void create_file_source_hook(); | ||||
|     virtual void create_throttle_hook(); | ||||
|     virtual void create_valve_hook(); | ||||
|     virtual void create_sink_hook(); | ||||
|  | ||||
|     // Subclass hooks for connection/disconnection | ||||
|     virtual void pre_connect_hook(gr::top_block_sptr top_block); | ||||
|     virtual void post_connect_hook(gr::top_block_sptr top_block); | ||||
|     virtual void pre_disconnect_hook(gr::top_block_sptr top_block); | ||||
|     virtual void post_disconnect_hook(gr::top_block_sptr top_block); | ||||
|  | ||||
| private: | ||||
|     std::string filename_; | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|  | ||||
|     std::string item_type_; | ||||
|     size_t item_size_; | ||||
|     bool is_complex_;  // a misnomer; if I/Q are interleaved as integer values | ||||
|  | ||||
|     size_t header_size_;  // length (in samples) of the header (if any) | ||||
|     double seconds_to_skip_; | ||||
|     bool repeat_; | ||||
|  | ||||
|     // The valve allows only the configured number of samples through, then it closes. | ||||
|  | ||||
|     // The framework passes the queue as a naked pointer, rather than a shared pointer, so this | ||||
|     // class has two choices: construct the valve in the ctor, or hold onto the pointer, possibly | ||||
|     // beyond its lifetime. Fortunately, the queue is only used to create the valve, so the | ||||
|     // likelihood of holding a stale pointer is mitigated | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_;  // why is this signed | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue_; | ||||
|  | ||||
|     bool enable_throttle_control_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|  | ||||
|     bool dump_; | ||||
|     std::string dump_filename_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -18,17 +18,21 @@ | ||||
|  | ||||
| #include "flexiband_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <teleorbit/frontend.h> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| FlexibandSignalSource::FlexibandSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, | ||||
|     unsigned int in_stream, | ||||
|     unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused))) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused))) | ||||
|     : SignalSourceBase(configuration, role, "Flexiband_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("byte"); | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
| #define GNSS_SDR_FLEXIBAND_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/char_to_float.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/float_to_complex.h> | ||||
| @@ -45,7 +45,7 @@ class ConfigurationInterface; | ||||
|  * \brief This class configures and reads samples from Teleorbit Flexiband front-end. | ||||
|  * This software requires a Flexiband GNU Radio driver installed (not included with GNSS-SDR). | ||||
|  */ | ||||
| class FlexibandSignalSource : public GNSSBlockInterface | ||||
| class FlexibandSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     FlexibandSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -54,19 +54,6 @@ public: | ||||
|  | ||||
|     ~FlexibandSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Flexiband_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Flexiband_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -85,7 +72,6 @@ private: | ||||
|     std::vector<boost::shared_ptr<gr::block>> float_to_complex_; | ||||
|     std::vector<gr::blocks::null_sink::sptr> null_sinks_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string firmware_filename_; | ||||
|     std::string signal_file; | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
| #include "ad9361_manager.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <algorithm>  // for max | ||||
| @@ -29,10 +30,12 @@ | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| Fmcomms2SignalSource::Fmcomms2SignalSource(const ConfigurationInterface *configuration, | ||||
|     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t> *queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t> *queue) | ||||
|     : SignalSourceBase(configuration, role, "Fmcomms2_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("gr_complex"); | ||||
|     const std::string default_dump_file("./data/signal_source.dat"); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
| #ifndef GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #if GRIIO_INCLUDE_HAS_GNURADIO | ||||
| #include <gnuradio/iio/fmcomms2_source.h> | ||||
| @@ -41,7 +41,7 @@ | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| class Fmcomms2SignalSource : public GNSSBlockInterface | ||||
| class Fmcomms2SignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     Fmcomms2SignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -50,19 +50,6 @@ public: | ||||
|  | ||||
|     ~Fmcomms2SignalSource(); | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Fmcomms2_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Fmcomms2_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -78,7 +65,6 @@ private: | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_interface.h" | ||||
| #include <pmt/pmt.h> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| @@ -37,16 +38,13 @@ | ||||
|  * \brief This class wraps blocks that generates synthesized GNSS signal and | ||||
|  * filters the signal. | ||||
|  */ | ||||
| class GenSignalSource : public GNSSBlockInterface | ||||
| class GenSignalSource : public SignalSourceInterface | ||||
| { | ||||
| public: | ||||
|     //! Constructor | ||||
|     GenSignalSource(std::shared_ptr<GNSSBlockInterface> signal_generator, std::shared_ptr<GNSSBlockInterface> filter, | ||||
|         std::string role, Concurrent_Queue<pmt::pmt_t> *queue); | ||||
|  | ||||
|     //! Virtual destructor | ||||
|     virtual ~GenSignalSource() = default; | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
| @@ -56,6 +54,8 @@ public: | ||||
|     //! Returns "Signal Source" | ||||
|     inline std::string implementation() override { return "Signal Source"; } | ||||
|     inline size_t item_size() override { return 0; } | ||||
|     inline size_t getRfChannels() const final { return 0; } | ||||
|  | ||||
|     inline std::shared_ptr<GNSSBlockInterface> signal_generator() const { return signal_generator_; } | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -16,16 +16,20 @@ | ||||
|  | ||||
| #include "gn3s_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gn3s/gn3s_source_cc.h> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| Gn3sSignalSource::Gn3sSignalSource(const ConfigurationInterface* configuration, | ||||
|     std::string role, | ||||
|     unsigned int in_stream, | ||||
|     unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Gn3s_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("short"); | ||||
|     const std::string default_dump_file("./data/gn3s_source.dat"); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| #define GNSS_SDR_GN3S_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| @@ -38,7 +38,7 @@ class ConfigurationInterface; | ||||
| /*! | ||||
|  * \brief This class reads samples from a GN3S USB dongle, a RF front-end signal sampler | ||||
|  */ | ||||
| class Gn3sSignalSource : public GNSSBlockInterface | ||||
| class Gn3sSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     Gn3sSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -47,19 +47,6 @@ public: | ||||
|  | ||||
|     ~Gn3sSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Gn3s_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Gn3s_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -73,11 +60,10 @@ public: | ||||
| private: | ||||
|     gr::block_sptr gn3s_source_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     size_t item_size_; | ||||
|     int64_t samples_; | ||||
|     [[maybe_unused]] int64_t samples_; | ||||
|     unsigned int in_stream_; | ||||
|     unsigned int out_stream_; | ||||
|     bool dump_; | ||||
|   | ||||
| @@ -16,14 +16,15 @@ | ||||
|  | ||||
| #include "labsat_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "labsat23_source.h" | ||||
| #include <glog/logging.h> | ||||
| #include <cstdint> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| LabsatSignalSource::LabsatSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Labsat_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("gr_complex"); | ||||
|     const std::string default_dump_file("./labsat_output.dat"); | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| @@ -38,7 +39,7 @@ class ConfigurationInterface; | ||||
| /*! | ||||
|  * \brief This class reads samples stored by a LabSat 2 or LabSat 3 device | ||||
|  */ | ||||
| class LabsatSignalSource : public GNSSBlockInterface | ||||
| class LabsatSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     LabsatSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -47,19 +48,6 @@ public: | ||||
|  | ||||
|     ~LabsatSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Labsat_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Labsat_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -75,7 +63,6 @@ private: | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string filename_; | ||||
|     std::string dump_filename_; | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include "multichannel_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| @@ -27,18 +28,21 @@ | ||||
| #include <utility> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| MultichannelFileSignalSource::MultichannelFileSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Multichannel_File_Signal_Source"s), in_streams_(in_streams), out_streams_(out_streams) | ||||
| { | ||||
|     const std::string default_filename("./example_capture.dat"); | ||||
|     const std::string default_item_type("short"); | ||||
|     const std::string default_dump_filename("./my_capture.dat"); | ||||
|     const std::string default_filename("./example_capture.dat"s); | ||||
|     const std::string default_item_type("short"s); | ||||
|     const std::string default_dump_filename("./my_capture.dat"s); | ||||
|  | ||||
|     const double default_seconds_to_skip = 0.0; | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     n_channels_ = configuration->property(role + ".total_channels", 1); | ||||
|     samples_ = configuration->property(role + ".samples"s, static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency"s, static_cast<int64_t>(0)); | ||||
|     n_channels_ = configuration->property(role + ".total_channels"s, 1); | ||||
|  | ||||
|     for (int32_t n = 0; n < n_channels_; n++) | ||||
|         { | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| @@ -45,7 +46,7 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from files at different frequency bands | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class MultichannelFileSignalSource : public GNSSBlockInterface | ||||
| class MultichannelFileSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     MultichannelFileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
| @@ -54,19 +55,6 @@ public: | ||||
|  | ||||
|     ~MultichannelFileSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Multichannel_File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Multichannel_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -109,7 +97,6 @@ private: | ||||
|     std::vector<gr::blocks::throttle::sptr> throttle_vec_; | ||||
|     std::vector<std::string> filename_vec_; | ||||
|     std::string item_type_; | ||||
|     std::string role_; | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     size_t item_size_; | ||||
|   | ||||
| @@ -10,286 +10,69 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "nsr_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| #include <iomanip> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| NsrFileSignalSource::NsrFileSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : FileSourceBase(configuration, role, "Nsr_File_Signal_Source"s, queue, "byte"s) | ||||
| { | ||||
|     const std::string default_filename("../data/my_capture.dat"); | ||||
|     const std::string default_item_type("byte"); | ||||
|     const std::string default_dump_filename("../data/my_capture_dump.dat"); | ||||
|  | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     filename_ = configuration->property(role + ".filename", default_filename); | ||||
|  | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
|  | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|     repeat_ = configuration->property(role + ".repeat", false); | ||||
|     dump_ = configuration->property(role + ".dump", false); | ||||
|     dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); | ||||
|     enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); | ||||
|  | ||||
|     if (item_type_ == "byte") | ||||
|         { | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|     try | ||||
|         { | ||||
|             file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); | ||||
|             unpack_byte_ = make_unpack_byte_2bit_samples(); | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             std::cerr | ||||
|                 << "The receiver was configured to work with a file signal source\n" | ||||
|                 << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                 << "Please modify your configuration file\n" | ||||
|                 << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                 << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                 << "Examples of configuration files available at:\n" | ||||
|                 << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n"; | ||||
|  | ||||
|             LOG(WARNING) << "file_signal_source: Unable to open the samples file " | ||||
|                          << filename_.c_str() << ", exiting the program."; | ||||
|             throw(e); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     if (samples_ == 0)  // read all file | ||||
|         { | ||||
|             /*! | ||||
|              * 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 2 milliseconds, and enable always the | ||||
|              * valve block | ||||
|              */ | ||||
|             std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||
|             std::ifstream::pos_type size; | ||||
|  | ||||
|             if (file.is_open()) | ||||
|                 { | ||||
|                     size = file.tellg(); | ||||
|                     LOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size())); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << '\n'; | ||||
|                     LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); | ||||
|                 } | ||||
|             std::streamsize ss = std::cout.precision(); | ||||
|             std::cout << std::setprecision(16); | ||||
|             std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]\n"; | ||||
|             std::cout.precision(ss); | ||||
|  | ||||
|             if (size > 0) | ||||
|                 { | ||||
|                     int sample_packet_factor = 4;  // 1 byte -> 4 samples | ||||
|                     samples_ = floor(static_cast<double>(size) / static_cast<double>(item_size())) * sample_packet_factor; | ||||
|                     samples_ = samples_ - ceil(0.002 * static_cast<double>(sampling_frequency_));  // process all the samples available in the file excluding the last 2 ms | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||
|     const double signal_duration_s = static_cast<double>(samples_) * (1 / static_cast<double>(sampling_frequency_)); | ||||
|     LOG(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"; | ||||
|  | ||||
|     valve_ = gnss_sdr_make_valve(sizeof(float), samples_, queue); | ||||
|     DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|     if (dump_) | ||||
|         { | ||||
|             // sink_ = gr_make_file_sink(item_size_, dump_filename_.c_str()); | ||||
|             sink_ = gr::blocks::file_sink::make(sizeof(float), dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|         } | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             throttle_ = gr::blocks::throttle::make(sizeof(float), sampling_frequency_); | ||||
|         } | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|     if (in_streams_ > 0) | ||||
|     if (in_streams > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "A signal source does not have an input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 1) | ||||
|     if (out_streams > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void NsrFileSignalSource::connect(gr::top_block_sptr top_block) | ||||
| std::tuple<size_t, bool> NsrFileSignalSource::itemTypeToSize() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|     auto is_complex = false; | ||||
|     auto item_size = size_t(sizeof(char));  // default | ||||
|  | ||||
|     if (item_type() == "byte") | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     top_block->connect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected file source to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             item_size = sizeof(char); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(throttle_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                             top_block->connect(unpack_byte_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             LOG(WARNING) << item_type() << " unrecognized item type. Using byte."; | ||||
|         } | ||||
|  | ||||
|     return std::make_tuple(item_size, is_complex); | ||||
| } | ||||
|  | ||||
| // 1 byte -> 4 samples | ||||
| double NsrFileSignalSource::packetsPerSample() const { return 4.0; } | ||||
| gnss_shared_ptr<gr::block> NsrFileSignalSource::source() const { return unpack_byte_; } | ||||
|  | ||||
| void NsrFileSignalSource::disconnect(gr::top_block_sptr top_block) | ||||
|  | ||||
| void NsrFileSignalSource::create_file_source_hook() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->connect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to throttle_"; | ||||
|                     top_block->disconnect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->disconnect(unpack_byte_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->disconnect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(unpack_byte_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected funpack_byte_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                             DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                             top_block->disconnect(unpack_byte_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected unpack_byte_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     unpack_byte_ = make_unpack_byte_2bit_samples(); | ||||
|     DLOG(INFO) << "unpack_byte_2bit_samples(" << unpack_byte_->unique_id() << ")"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr NsrFileSignalSource::get_left_block() | ||||
| void NsrFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     // return gr_block_sptr(); | ||||
|     return gr::blocks::file_source::sptr(); | ||||
|     top_block->connect(file_source(), 0, unpack_byte_, 0); | ||||
|     DLOG(INFO) << "connected file_source to unpacker"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr NsrFileSignalSource::get_right_block() | ||||
| void NsrFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             return valve_; | ||||
|         } | ||||
|     if (enable_throttle_control_ == true) | ||||
|         { | ||||
|             return throttle_; | ||||
|         } | ||||
|     return unpack_byte_; | ||||
|     top_block->disconnect(file_source(), 0, unpack_byte_, 0); | ||||
|     DLOG(INFO) << "disconnected file_source from unpacker"; | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
| @@ -21,15 +21,8 @@ | ||||
| #ifndef GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "file_source_base.h" | ||||
| #include "unpack_byte_2bit_samples.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <string> | ||||
|  | ||||
| /** \addtogroup Signal_Source | ||||
|  * \{ */ | ||||
| @@ -42,7 +35,7 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class NsrFileSignalSource : public GNSSBlockInterface | ||||
| class NsrFileSignalSource : public FileSourceBase | ||||
| { | ||||
| public: | ||||
|     NsrFileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
| @@ -50,73 +43,17 @@ public: | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue); | ||||
|  | ||||
|     ~NsrFileSignalSource() = default; | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Nsr_File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Nsr_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     inline std::string filename() const | ||||
|     { | ||||
|         return filename_; | ||||
|     } | ||||
|  | ||||
|     inline std::string item_type() const | ||||
|     { | ||||
|         return item_type_; | ||||
|     } | ||||
|  | ||||
|     inline bool repeat() const | ||||
|     { | ||||
|         return repeat_; | ||||
|     } | ||||
|  | ||||
|     inline int64_t sampling_frequency() const | ||||
|     { | ||||
|         return sampling_frequency_; | ||||
|     } | ||||
|  | ||||
|     inline uint64_t samples() const | ||||
|     { | ||||
|         return samples_; | ||||
|     } | ||||
| protected: | ||||
|     std::tuple<size_t, bool> itemTypeToSize() override; | ||||
|     double packetsPerSample() const override; | ||||
|     gnss_shared_ptr<gr::block> source() const override; | ||||
|     void create_file_source_hook() override; | ||||
|     void pre_connect_hook(gr::top_block_sptr top_block) override; | ||||
|     void pre_disconnect_hook(gr::top_block_sptr top_block) override; | ||||
|  | ||||
| private: | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|     unpack_byte_2bit_samples_sptr unpack_byte_; | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     size_t item_size_; | ||||
|     std::string filename_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|     uint32_t in_streams_; | ||||
|     uint32_t out_streams_; | ||||
|     bool repeat_; | ||||
|     bool dump_; | ||||
|     // Throttle control | ||||
|     bool enable_throttle_control_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include "osmosdr_signal_source.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| @@ -25,9 +26,13 @@ | ||||
| #include <utility> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| OsmosdrSignalSource::OsmosdrSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Osmosdr_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     // DUMP PARAMETERS | ||||
|     const std::string empty; | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
| #define GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| @@ -42,7 +42,7 @@ class ConfigurationInterface; | ||||
|  * HackRF or Realtek's RTL2832U-based USB dongle DVB-T receivers | ||||
|  * (see https://osmocom.org/projects/rtl-sdr/wiki) | ||||
|  */ | ||||
| class OsmosdrSignalSource : public GNSSBlockInterface | ||||
| class OsmosdrSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     OsmosdrSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -51,19 +51,6 @@ public: | ||||
|  | ||||
|     ~OsmosdrSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Osmosdr_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Osmosdr_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -81,7 +68,6 @@ private: | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string osmosdr_args_; | ||||
|   | ||||
| @@ -18,15 +18,20 @@ | ||||
| #include "plutosdr_signal_source.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| PlutosdrSignalSource::PlutosdrSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Plutosdr_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("gr_complex"); | ||||
|     const std::string default_dump_file("./data/signal_source.dat"); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| #ifndef GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #if GRIIO_INCLUDE_HAS_GNURADIO | ||||
| #include <gnuradio/iio/pluto_source.h> | ||||
| @@ -42,7 +42,7 @@ class ConfigurationInterface; | ||||
|  | ||||
| /*! | ||||
|  */ | ||||
| class PlutosdrSignalSource : public GNSSBlockInterface | ||||
| class PlutosdrSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     PlutosdrSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -51,18 +51,6 @@ public: | ||||
|  | ||||
|     ~PlutosdrSignalSource() = default; | ||||
|  | ||||
|     std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Plutosdr_Signal_Source" | ||||
|      */ | ||||
|     std::string implementation() override | ||||
|     { | ||||
|         return "Plutosdr_Signal_Source"; | ||||
|     } | ||||
|     size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -79,7 +67,6 @@ private: | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string dump_filename_; | ||||
|  | ||||
|     // Front-end settings | ||||
|   | ||||
| @@ -17,14 +17,18 @@ | ||||
| #include "raw_array_signal_source.h" | ||||
| #include "concurrent_queue.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <dbfcttc/raw_array.h> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| RawArraySignalSource::RawArraySignalSource(const ConfigurationInterface* configuration, | ||||
|     std::string role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     std::string role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Raw_Array_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     const std::string default_item_type("gr_complex"); | ||||
|     const std::string default_dump_file("./data/raw_array_source.dat"); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| #define GNSS_SDR_RAW_ARRAY_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| @@ -39,7 +39,7 @@ class ConfigurationInterface; | ||||
| /*! | ||||
|  * \brief This class reads samples from a GN3S USB dongle, a RF front-end signal sampler | ||||
|  */ | ||||
| class RawArraySignalSource : public GNSSBlockInterface | ||||
| class RawArraySignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     RawArraySignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -48,19 +48,6 @@ public: | ||||
|  | ||||
|     ~RawArraySignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "RawArraySignalSource". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Raw_Array_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -74,12 +61,11 @@ public: | ||||
| private: | ||||
|     gr::block_sptr raw_array_source_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string eth_device_; | ||||
|     size_t item_size_; | ||||
|     int64_t samples_; | ||||
|     [[maybe_unused]] int64_t samples_; | ||||
|     unsigned int in_stream_; | ||||
|     unsigned int out_stream_; | ||||
|     bool dump_; | ||||
|   | ||||
| @@ -19,20 +19,21 @@ | ||||
| #include "rtl_tcp_signal_source.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <cstdint> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| RtlTcpSignalSource::RtlTcpSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, | ||||
|     unsigned int in_stream, | ||||
|     unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), | ||||
|                                            in_stream_(in_stream), | ||||
|                                            out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "RtlTcp_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     // DUMP PARAMETERS | ||||
|     const std::string default_dump_file("./data/signal_source.dat"); | ||||
|   | ||||
| @@ -19,8 +19,8 @@ | ||||
| #define GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "rtl_tcp_signal_source_c.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/deinterleave.h> | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/float_to_complex.h> | ||||
| @@ -42,7 +42,7 @@ class ConfigurationInterface; | ||||
|  * I/Q samples over TCP. | ||||
|  * (see https://osmocom.org/projects/rtl-sdr/wiki) | ||||
|  */ | ||||
| class RtlTcpSignalSource : public GNSSBlockInterface | ||||
| class RtlTcpSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     RtlTcpSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -53,19 +53,6 @@ public: | ||||
|  | ||||
|     ~RtlTcpSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "RtlTcp_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "RtlTcp_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -84,7 +71,6 @@ private: | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr file_sink_; | ||||
|  | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|  | ||||
|   | ||||
							
								
								
									
										46
									
								
								src/algorithms/signal_source/adapters/signal_source_base.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/algorithms/signal_source/adapters/signal_source_base.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| /*! | ||||
|  * \file signal_source_base.cc | ||||
|  * \brief Base class for signal sources | ||||
|  * \author Jim Melton, 2020. jim.melton(at)sncorp.com | ||||
|  * | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "signal_source_base.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <utility>  // move | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| std::string SignalSourceBase::role() | ||||
| { | ||||
|     return role_; | ||||
| } | ||||
|  | ||||
| std::string SignalSourceBase::implementation() | ||||
| { | ||||
|     return implementation_; | ||||
| } | ||||
|  | ||||
| size_t SignalSourceBase::getRfChannels() const | ||||
| { | ||||
|     return rfChannels_; | ||||
| } | ||||
|  | ||||
| SignalSourceBase::SignalSourceBase(ConfigurationInterface const* configuration, std::string role, std::string impl) | ||||
|     : role_(std::move(role)), implementation_(std::move(impl)) | ||||
| { | ||||
|     // because clang-tidy insists on using std::move for the string arguments, and to avoid | ||||
|     // depending on the order of initialization, assign rfChannels_ in the body | ||||
|     rfChannels_ = configuration->property(role_ + ".RF_channels"s, uint64_t(1U)); | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/algorithms/signal_source/adapters/signal_source_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/algorithms/signal_source/adapters/signal_source_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /*! | ||||
|  * \file signal_source_base.h | ||||
|  * \brief Header file of the base class to signal_source GNSS blocks. | ||||
|  * \author Jim Melton, 2020. jim.melton(at)sncorp.com | ||||
|  * | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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_SIGNAL_SOURCE_BASE_H | ||||
| #define GNSS_SDR_SIGNAL_SOURCE_BASE_H | ||||
|  | ||||
| #include "signal_source_interface.h" | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| class SignalSourceBase : public SignalSourceInterface | ||||
| { | ||||
| public: | ||||
|     std::string role() final; | ||||
|     std::string implementation() final; | ||||
|  | ||||
|     size_t getRfChannels() const override; | ||||
|  | ||||
| protected: | ||||
|     //! Constructor | ||||
|     SignalSourceBase(ConfigurationInterface const* configuration, std::string role, std::string impl); | ||||
|  | ||||
| private: | ||||
|     std::string const role_; | ||||
|     std::string const implementation_; | ||||
|     size_t rfChannels_; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -6,290 +6,74 @@ | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is not part of GNSS-SDR. | ||||
|  * 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 | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "spir_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| #include <iomanip> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| SpirFileSignalSource::SpirFileSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : FileSourceBase(configuration, role, "Spir_File_Signal_Source"s, queue, "int"s) | ||||
| { | ||||
|     const std::string default_filename("../data/my_capture.dat"); | ||||
|     const std::string default_item_type("int"); | ||||
|     const std::string default_dump_filename("../data/my_capture_dump.dat"); | ||||
|  | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     filename_ = configuration->property(role + ".filename", default_filename); | ||||
|  | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
|  | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|     repeat_ = configuration->property(role + ".repeat", false); | ||||
|     dump_ = configuration->property(role + ".dump", false); | ||||
|     dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); | ||||
|     enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); | ||||
|  | ||||
|     if (item_type_ == "int") | ||||
|         { | ||||
|             item_size_ = sizeof(int); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ << " unrecognized item type. Using int."; | ||||
|             item_size_ = sizeof(int); | ||||
|         } | ||||
|     try | ||||
|         { | ||||
|             file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); | ||||
|             unpack_intspir_ = make_unpack_intspir_1bit_samples(); | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             std::cerr | ||||
|                 << "The receiver was configured to work with a file signal source\n" | ||||
|                 << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                 << "Please modify your configuration file\n" | ||||
|                 << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                 << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                 << "Examples of configuration files available at:\n" | ||||
|                 << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n"; | ||||
|  | ||||
|             LOG(WARNING) << "file_signal_source: Unable to open the samples file " | ||||
|                          << filename_.c_str() << ", exiting the program."; | ||||
|             throw(e); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     if (samples_ == 0)  // read all file | ||||
|         { | ||||
|             /*! | ||||
|              * 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(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||
|             std::ifstream::pos_type size; | ||||
|  | ||||
|             if (file.is_open()) | ||||
|                 { | ||||
|                     size = file.tellg(); | ||||
|                     LOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size())); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << '\n'; | ||||
|                     LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); | ||||
|                 } | ||||
|             std::streamsize ss = std::cout.precision(); | ||||
|             std::cout << std::setprecision(16); | ||||
|             std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]\n"; | ||||
|             std::cout.precision(ss); | ||||
|  | ||||
|             if (size > 0) | ||||
|                 { | ||||
|                     int sample_packet_factor = 1;  // 1 int -> 1 complex sample (I&Q from 1 channel) | ||||
|                     samples_ = floor(static_cast<double>(size) / static_cast<double>(item_size())) * sample_packet_factor; | ||||
|                     samples_ = samples_ - ceil(0.002 * static_cast<double>(sampling_frequency_));  // process all the samples available in the file excluding the last 2 ms | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||
|     double signal_duration_s = static_cast<double>(samples_) * (1 / static_cast<double>(sampling_frequency_)); | ||||
|     LOG(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"; | ||||
|  | ||||
|     valve_ = gnss_sdr_make_valve(sizeof(float), samples_, queue); | ||||
|     DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|     if (dump_) | ||||
|         { | ||||
|             // sink_ = gr_make_file_sink(item_size_, dump_filename_.c_str()); | ||||
|             sink_ = gr::blocks::file_sink::make(sizeof(float), dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|         } | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             throttle_ = gr::blocks::throttle::make(sizeof(float), sampling_frequency_); | ||||
|         } | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|     if (in_streams_ > 0) | ||||
|     if (in_streams > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "A signal source does not have an input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 1) | ||||
|     if (out_streams > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void SpirFileSignalSource::connect(gr::top_block_sptr top_block) | ||||
| std::tuple<size_t, bool> SpirFileSignalSource::itemTypeToSize() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|     auto is_complex = false; | ||||
|     auto item_size = size_t(0); | ||||
|  | ||||
|     if (item_type() == "int") | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     top_block->connect(unpack_intspir_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     top_block->connect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     top_block->connect(unpack_intspir_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected file source to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             item_size = sizeof(int); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     top_block->connect(unpack_intspir_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(throttle_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(file_source_, 0, unpack_intspir_, 0); | ||||
|                             top_block->connect(unpack_intspir_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             LOG(WARNING) << item_type() << " unsupported item type. Using int."; | ||||
|             item_size = sizeof(int); | ||||
|         } | ||||
|  | ||||
|     return std::make_tuple(item_size, is_complex); | ||||
| } | ||||
|  | ||||
| // This class feeds the file data through a decoder to produce samples; for all intents this is the "source" | ||||
| gnss_shared_ptr<gr::block> SpirFileSignalSource::source() const { return unpack_intspir_; } | ||||
|  | ||||
| void SpirFileSignalSource::disconnect(gr::top_block_sptr top_block) | ||||
|  | ||||
| void SpirFileSignalSource::create_file_source_hook() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_intspir_"; | ||||
|                     top_block->connect(unpack_intspir_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_intspir_ to throttle_"; | ||||
|                     top_block->disconnect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_intspir_"; | ||||
|                     top_block->disconnect(unpack_intspir_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_intspir_ to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_intspir_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_intspir_"; | ||||
|                     top_block->disconnect(unpack_intspir_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_intspir_ to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(unpack_intspir_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected funpack_intspir_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(file_source_, 0, unpack_intspir_, 0); | ||||
|                             DLOG(INFO) << "disconnected file source to unpack_intspir_"; | ||||
|                             top_block->disconnect(unpack_intspir_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected unpack_intspir_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     // connect the file to the decoder | ||||
|     unpack_intspir_ = make_unpack_intspir_1bit_samples(); | ||||
|     DLOG(INFO) << "unpack_intspir_1bit_samples(" << unpack_intspir_->unique_id() << ")"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr SpirFileSignalSource::get_left_block() | ||||
| void SpirFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     // return gr_block_sptr(); | ||||
|     return gr::blocks::file_source::sptr(); | ||||
|     top_block->connect(file_source(), 0, unpack_intspir_, 0); | ||||
|     DLOG(INFO) << "connected file_source to unpacker"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr SpirFileSignalSource::get_right_block() | ||||
| void SpirFileSignalSource::post_disconnect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             return valve_; | ||||
|         } | ||||
|     if (enable_throttle_control_ == true) | ||||
|         { | ||||
|             return throttle_; | ||||
|         } | ||||
|     return unpack_intspir_; | ||||
|     top_block->disconnect(file_source(), 0, unpack_intspir_, 0); | ||||
|     DLOG(INFO) << "disconnected file_source from unpacker"; | ||||
| } | ||||
|   | ||||
| @@ -6,13 +6,10 @@ | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
|  * | ||||
|  * This file is not part of GNSS-SDR. | ||||
|  * 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 | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
| @@ -21,16 +18,8 @@ | ||||
| #ifndef GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "file_source_base.h" | ||||
| #include "unpack_intspir_1bit_samples.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| /** \addtogroup Signal_Source | ||||
| @@ -45,7 +34,7 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class SpirFileSignalSource : public GNSSBlockInterface | ||||
| class SpirFileSignalSource : public FileSourceBase | ||||
| { | ||||
| public: | ||||
|     SpirFileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
| @@ -54,77 +43,16 @@ public: | ||||
|  | ||||
|     ~SpirFileSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
| protected: | ||||
|     std::tuple<size_t, bool> itemTypeToSize() override; | ||||
|     gnss_shared_ptr<gr::block> source() const override; | ||||
|     void create_file_source_hook() override; | ||||
|     void pre_connect_hook(gr::top_block_sptr top_block) override; | ||||
|     void post_disconnect_hook(gr::top_block_sptr top_block) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Spir_File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Spir_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     inline std::string filename() const | ||||
|     { | ||||
|         return filename_; | ||||
|     } | ||||
|  | ||||
|     inline std::string item_type() const | ||||
|     { | ||||
|         return item_type_; | ||||
|     } | ||||
|  | ||||
|     inline bool repeat() const | ||||
|     { | ||||
|         return repeat_; | ||||
|     } | ||||
|  | ||||
|     inline int64_t sampling_frequency() const | ||||
|     { | ||||
|         return sampling_frequency_; | ||||
|     } | ||||
|  | ||||
|     inline uint64_t samples() const | ||||
|     { | ||||
|         return samples_; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|     unpack_intspir_1bit_samples_sptr unpack_intspir_; | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|     std::string filename_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|  | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     size_t item_size_; | ||||
|  | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|  | ||||
|     bool repeat_; | ||||
|     bool dump_; | ||||
|  | ||||
|     // Throttle control | ||||
|     bool enable_throttle_control_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
|  | ||||
| #include "spir_gss6450_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| @@ -25,9 +26,11 @@ | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, uint32_t in_streams, uint32_t out_streams, Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
|     const std::string& role, uint32_t in_streams, uint32_t out_streams, Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "Spir_GSS6450_File_Signal_Source"s), in_streams_(in_streams), out_streams_(out_streams) | ||||
| { | ||||
|     const std::string default_filename("../data/my_capture.dat"); | ||||
|     const std::string default_dump_filename("../data/my_capture_dump.dat"); | ||||
|   | ||||
| @@ -22,8 +22,8 @@ | ||||
| #define GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "signal_source_base.h" | ||||
| #include "unpack_spir_gss6450_samples.h" | ||||
| #include <gnuradio/blocks/deinterleave.h> | ||||
| #include <gnuradio/blocks/endian_swap.h> | ||||
| @@ -50,23 +50,12 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class SpirGSS6450FileSignalSource : public GNSSBlockInterface | ||||
| class SpirGSS6450FileSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     SpirGSS6450FileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
|         uint32_t in_streams, uint32_t out_streams, Concurrent_Queue<pmt::pmt_t>* queue); | ||||
|  | ||||
|     ~SpirGSS6450FileSignalSource() = default; | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Spir_GSS6450_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -114,7 +103,6 @@ private: | ||||
|     std::vector<gr::blocks::throttle::sptr> throttle_vec_; | ||||
|     std::string filename_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|     std::string item_type_; | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|   | ||||
| @@ -9,296 +9,77 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "two_bit_cpx_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| #include <iomanip> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource( | ||||
|     const ConfigurationInterface* configuration, | ||||
|     const std::string& role, | ||||
|     unsigned int in_streams, | ||||
|     unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), | ||||
|                                            in_streams_(in_streams), | ||||
|                                            out_streams_(out_streams) | ||||
|     unsigned int in_streams, unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : FileSourceBase(configuration, role, "Two_Bit_Cpx_File_Signal_Source"s, queue, "byte"s) | ||||
| { | ||||
|     const std::string default_filename("../data/my_capture.dat"); | ||||
|     const std::string default_item_type("byte"); | ||||
|     const std::string default_dump_filename("../data/my_capture_dump.dat"); | ||||
|  | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     filename_ = configuration->property(role + ".filename", default_filename); | ||||
|  | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
|  | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|     repeat_ = configuration->property(role + ".repeat", false); | ||||
|     dump_ = configuration->property(role + ".dump", false); | ||||
|     dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); | ||||
|     enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); | ||||
|  | ||||
|     if (item_type_ == "byte") | ||||
|         { | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|     try | ||||
|         { | ||||
|             file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); | ||||
|             unpack_byte_ = make_unpack_byte_2bit_cpx_samples(); | ||||
|             inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, true);  // I/Q swap enabled | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             std::cerr | ||||
|                 << "The receiver was configured to work with a file signal source\n" | ||||
|                 << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                 << "Please modify your configuration file\n" | ||||
|                 << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                 << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                 << "Examples of configuration files available at:\n" | ||||
|                 << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n"; | ||||
|  | ||||
|             LOG(WARNING) << "file_signal_source: Unable to open the samples file " | ||||
|                          << filename_.c_str() << ", exiting the program."; | ||||
|             throw(e); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     if (samples_ == 0)  // read all file | ||||
|         { | ||||
|             /*! | ||||
|              * 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 2 milliseconds, and enable always the | ||||
|              * valve block | ||||
|              */ | ||||
|             std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||
|             std::ifstream::pos_type size; | ||||
|  | ||||
|             if (file.is_open()) | ||||
|                 { | ||||
|                     size = file.tellg(); | ||||
|                     LOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size())); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << '\n'; | ||||
|                     LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); | ||||
|                 } | ||||
|             std::streamsize ss = std::cout.precision(); | ||||
|             std::cout << std::setprecision(16); | ||||
|             std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]\n"; | ||||
|             std::cout.precision(ss); | ||||
|  | ||||
|             if (size > 0) | ||||
|                 { | ||||
|                     int sample_packet_factor = 2;  // 1 byte -> 2 samples | ||||
|                     samples_ = floor(static_cast<double>(size) / static_cast<double>(item_size())) * sample_packet_factor; | ||||
|                     samples_ = samples_ - ceil(0.002 * static_cast<double>(sampling_frequency_));  // process all the samples available in the file excluding the last 2 ms | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||
|     const double signal_duration_s = static_cast<double>(samples_) * (1 / static_cast<double>(sampling_frequency_)); | ||||
|     LOG(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"; | ||||
|  | ||||
|     valve_ = gnss_sdr_make_valve(sizeof(gr_complex), samples_, queue); | ||||
|     DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|     if (dump_) | ||||
|         { | ||||
|             // sink_ = gr_make_file_sink(item_size_, dump_filename_.c_str()); | ||||
|             sink_ = gr::blocks::file_sink::make(sizeof(gr_complex), dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|         } | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             throttle_ = gr::blocks::throttle::make(sizeof(gr_complex), sampling_frequency_); | ||||
|         } | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|     if (in_streams_ > 0) | ||||
|     if (in_streams > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "A signal source does not have an input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 1) | ||||
|     if (out_streams > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void TwoBitCpxFileSignalSource::connect(gr::top_block_sptr top_block) | ||||
| std::tuple<size_t, bool> TwoBitCpxFileSignalSource::itemTypeToSize() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|     auto is_complex = false; | ||||
|     auto item_size = size_t(sizeof(char));  // default | ||||
|  | ||||
|     if (item_type() == "byte") | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|                     top_block->connect(inter_shorts_to_cpx_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     top_block->connect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|                     top_block->connect(inter_shorts_to_cpx_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "connected file source to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             item_size = sizeof(char); | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                     top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|                     top_block->connect(inter_shorts_to_cpx_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "connected file source to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(throttle_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->connect(file_source_, 0, unpack_byte_, 0); | ||||
|                             top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|                             top_block->connect(inter_shorts_to_cpx_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "connected file source to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             LOG(WARNING) << item_type() << " unrecognized item type. Using byte."; | ||||
|         } | ||||
|  | ||||
|     return std::make_tuple(item_size, is_complex); | ||||
| } | ||||
|  | ||||
| // 1 byte -> 2 samples | ||||
| double TwoBitCpxFileSignalSource::packetsPerSample() const { return 2.0; } | ||||
| gnss_shared_ptr<gr::block> TwoBitCpxFileSignalSource::source() const { return inter_shorts_to_cpx_; } | ||||
|  | ||||
| void TwoBitCpxFileSignalSource::disconnect(gr::top_block_sptr top_block) | ||||
|  | ||||
| void TwoBitCpxFileSignalSource::create_file_source_hook() | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->connect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to throttle_"; | ||||
|                     top_block->disconnect(throttle_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected throttle to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->disconnect(unpack_byte_, 0, valve_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to valve"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             if (enable_throttle_control_ == true) | ||||
|                 { | ||||
|                     top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                     DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                     top_block->disconnect(unpack_byte_, 0, throttle_, 0); | ||||
|                     DLOG(INFO) << "disconnected unpack_byte_ to throttle"; | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(unpack_byte_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected funpack_byte_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     if (dump_) | ||||
|                         { | ||||
|                             top_block->disconnect(file_source_, 0, unpack_byte_, 0); | ||||
|                             DLOG(INFO) << "disconnected file source to unpack_byte_"; | ||||
|                             top_block->disconnect(unpack_byte_, 0, sink_, 0); | ||||
|                             DLOG(INFO) << "disconnected unpack_byte_ to sink"; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     unpack_byte_ = make_unpack_byte_2bit_cpx_samples(); | ||||
|     DLOG(INFO) << "unpack_byte_2bit_cpx_samples(" << unpack_byte_->unique_id() << ")"; | ||||
|     inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, true);  // I/Q swap enabled | ||||
|     DLOG(INFO) << "interleaved_short_to_complex(" << inter_shorts_to_cpx_->unique_id() << ")"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr TwoBitCpxFileSignalSource::get_left_block() | ||||
| void TwoBitCpxFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     // return gr_block_sptr(); | ||||
|     return gr::blocks::file_source::sptr(); | ||||
|     top_block->connect(file_source(), 0, unpack_byte_, 0); | ||||
|     top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|     DLOG(INFO) << "connected file_source to unpacker"; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr TwoBitCpxFileSignalSource::get_right_block() | ||||
| void TwoBitCpxFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (samples_ > 0) | ||||
|         { | ||||
|             return valve_; | ||||
|         } | ||||
|     if (enable_throttle_control_ == true) | ||||
|         { | ||||
|             return throttle_; | ||||
|         } | ||||
|     return unpack_byte_; | ||||
|     top_block->disconnect(file_source(), 0, unpack_byte_, 0); | ||||
|     top_block->disconnect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); | ||||
|     DLOG(INFO) << "disconnected file_source from unpacker"; | ||||
| } | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
| @@ -20,17 +20,9 @@ | ||||
| #ifndef GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "file_source_base.h" | ||||
| #include "unpack_byte_2bit_cpx_samples.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/interleaved_short_to_complex.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| /** \addtogroup Signal_Source | ||||
|  * \{ */ | ||||
| @@ -44,7 +36,7 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class TwoBitCpxFileSignalSource : public GNSSBlockInterface | ||||
| class TwoBitCpxFileSignalSource : public FileSourceBase | ||||
| { | ||||
| public: | ||||
|     TwoBitCpxFileSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -54,74 +46,18 @@ public: | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue); | ||||
|  | ||||
|     ~TwoBitCpxFileSignalSource() = default; | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Two_Bit_Cpx_File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Two_Bit_Cpx_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     inline std::string filename() const | ||||
|     { | ||||
|         return filename_; | ||||
|     } | ||||
|  | ||||
|     inline std::string item_type() const | ||||
|     { | ||||
|         return item_type_; | ||||
|     } | ||||
|  | ||||
|     inline bool repeat() const | ||||
|     { | ||||
|         return repeat_; | ||||
|     } | ||||
|  | ||||
|     inline int64_t sampling_frequency() const | ||||
|     { | ||||
|         return sampling_frequency_; | ||||
|     } | ||||
|  | ||||
|     inline uint64_t samples() const | ||||
|     { | ||||
|         return samples_; | ||||
|     } | ||||
| protected: | ||||
|     std::tuple<size_t, bool> itemTypeToSize() override; | ||||
|     double packetsPerSample() const override; | ||||
|     gnss_shared_ptr<gr::block> source() const override; | ||||
|     void create_file_source_hook() override; | ||||
|     void pre_connect_hook(gr::top_block_sptr top_block) override; | ||||
|     void pre_disconnect_hook(gr::top_block_sptr top_block) override; | ||||
|  | ||||
| private: | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|     gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_; | ||||
|     unpack_byte_2bit_cpx_samples_sptr unpack_byte_; | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|     std::string filename_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|     size_t item_size_; | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|     bool repeat_; | ||||
|     bool dump_; | ||||
|     // Throttle control | ||||
|     bool enable_throttle_control_; | ||||
|     gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors) | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
| @@ -18,291 +18,122 @@ | ||||
|  | ||||
| #include "two_bit_packed_file_signal_source.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/blocks/char_to_float.h> | ||||
| #include <exception> | ||||
| #include <fstream> | ||||
| #include <iomanip> | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
| TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource( | ||||
|     const ConfigurationInterface* configuration, | ||||
|     const std::string& role, | ||||
|     unsigned int in_streams, | ||||
|     unsigned int out_streams, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), | ||||
|                                            in_streams_(in_streams), | ||||
|                                            out_streams_(out_streams) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : FileSourceBase(configuration, role, "Two_Bit_Packed_File_Signal_Source"s, queue, "byte"s), sample_type_(configuration->property(role + ".sample_type", "real"s)),  // options: "real", "iq", "qi" | ||||
|       big_endian_items_(configuration->property(role + ".big_endian_items", true)), | ||||
|       big_endian_bytes_(configuration->property(role + ".big_endian_bytes", false)), | ||||
|       reverse_interleaving_(false) | ||||
| { | ||||
|     const std::string default_filename("../data/my_capture.dat"); | ||||
|     const std::string default_item_type("byte"); | ||||
|     const std::string default_dump_filename("../data/my_capture_dump.dat"); | ||||
|     const std::string default_sample_type("real"); | ||||
|     const double default_seconds_to_skip = 0.0; | ||||
|  | ||||
|     samples_ = configuration->property(role + ".samples", static_cast<uint64_t>(0)); | ||||
|     sampling_frequency_ = configuration->property(role + ".sampling_frequency", static_cast<int64_t>(0)); | ||||
|     filename_ = configuration->property(role + ".filename", default_filename); | ||||
|  | ||||
|     // override value with commandline flag, if present | ||||
|     if (FLAGS_signal_source != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_signal_source; | ||||
|         } | ||||
|     if (FLAGS_s != "-") | ||||
|         { | ||||
|             filename_ = FLAGS_s; | ||||
|         } | ||||
|  | ||||
|     item_type_ = configuration->property(role + ".item_type", default_item_type); | ||||
|     big_endian_items_ = configuration->property(role + ".big_endian_items", true); | ||||
|     big_endian_bytes_ = configuration->property(role + ".big_endian_bytes", false); | ||||
|     sample_type_ = configuration->property(role + ".sample_type", default_sample_type);  // options: "real", "iq", "qi" | ||||
|     repeat_ = configuration->property(role + ".repeat", false); | ||||
|     dump_ = configuration->property(role + ".dump", false); | ||||
|     dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); | ||||
|     enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); | ||||
|     const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); | ||||
|     int64_t bytes_to_skip = 0; | ||||
|  | ||||
|     if (item_type_ == "byte") | ||||
|         { | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|     else if (item_type_ == "short") | ||||
|         { | ||||
|             // If we have shorts stored in little endian format, might as | ||||
|             // well read them in as bytes. | ||||
|             if (big_endian_items_) | ||||
|                 { | ||||
|                     item_size_ = sizeof(int16_t); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     item_size_ = sizeof(char); | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type_ << " unrecognized item type. Using byte."; | ||||
|             item_size_ = sizeof(char); | ||||
|         } | ||||
|  | ||||
|     reverse_interleaving_ = false; | ||||
|     is_complex_ = true; | ||||
|     if (sample_type_ == "real") | ||||
|         { | ||||
|             is_complex_ = false; | ||||
|         } | ||||
|     else if (sample_type_ == "iq") | ||||
|         { | ||||
|             is_complex_ = true; | ||||
|         } | ||||
|     else if (sample_type_ == "qi") | ||||
|         { | ||||
|             is_complex_ = true; | ||||
|             reverse_interleaving_ = true; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: " | ||||
|                          << (is_complex_ ? (reverse_interleaving_ ? "qi" : "iq") : "real"); | ||||
|         } | ||||
|     try | ||||
|         { | ||||
|             file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); | ||||
|  | ||||
|             if (seconds_to_skip > 0) | ||||
|                 { | ||||
|                     bytes_to_skip = static_cast<int64_t>( | ||||
|                         seconds_to_skip * sampling_frequency_ / 4); | ||||
|                     if (is_complex_) | ||||
|                         { | ||||
|                             bytes_to_skip <<= 1; | ||||
|                         } | ||||
|                     file_source_->seek(bytes_to_skip, SEEK_SET); | ||||
|                 } | ||||
|  | ||||
|             unpack_samples_ = make_unpack_2bit_samples(big_endian_bytes_, | ||||
|                 item_size_, big_endian_items_, reverse_interleaving_); | ||||
|             if (is_complex_) | ||||
|                 { | ||||
|                     char_to_float_ = | ||||
|                         gr::blocks::interleaved_char_to_complex::make(false); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     char_to_float_ = | ||||
|                         gr::blocks::char_to_float::make(); | ||||
|                 } | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             std::cerr | ||||
|                 << "The receiver was configured to work with a file signal source\n" | ||||
|                 << "but the specified file is unreachable by GNSS-SDR.\n" | ||||
|                 << "Please modify your configuration file\n" | ||||
|                 << "and point SignalSource.filename to a valid raw data file. Then:\n" | ||||
|                 << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf\n" | ||||
|                 << "Examples of configuration files available at:\n" | ||||
|                 << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/\n"; | ||||
|  | ||||
|             LOG(WARNING) << "file_signal_source: Unable to open the samples file " | ||||
|                          << filename_.c_str() << ", exiting the program."; | ||||
|             throw(e); | ||||
|         } | ||||
|  | ||||
|     DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; | ||||
|  | ||||
|     const size_t output_item_size = (is_complex_ ? sizeof(gr_complex) : sizeof(float)); | ||||
|  | ||||
|     if (samples_ == 0)  // read all file | ||||
|         { | ||||
|             /*! | ||||
|              * 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 2 milliseconds, and enable always the | ||||
|              * valve block | ||||
|              */ | ||||
|             std::ifstream file(filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||
|             std::ifstream::pos_type size; | ||||
|  | ||||
|             if (file.is_open()) | ||||
|                 { | ||||
|                     size = file.tellg(); | ||||
|                     samples_ = floor(static_cast<double>(size) * (is_complex_ ? 2.0 : 4.0)); | ||||
|                     LOG(INFO) << "Total samples in the file= " << samples_;  // 4 samples per byte | ||||
|                     samples_ -= bytes_to_skip; | ||||
|  | ||||
|                     // Also skip the last two milliseconds: | ||||
|                     samples_ -= ceil(0.002 * sampling_frequency_ / (is_complex_ ? 2.0 : 4.0)); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << '\n'; | ||||
|                     LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); | ||||
|                 } | ||||
|             std::streamsize ss = std::cout.precision(); | ||||
|             std::cout << std::setprecision(16); | ||||
|             std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]\n"; | ||||
|             std::cout.precision(ss); | ||||
|         } | ||||
|  | ||||
|     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||
|     double signal_duration_s; | ||||
|     signal_duration_s = static_cast<double>(samples_) * (1 / static_cast<double>(sampling_frequency_)); | ||||
|     LOG(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"; | ||||
|  | ||||
|     valve_ = gnss_sdr_make_valve(output_item_size, samples_, queue); | ||||
|     DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||
|  | ||||
|     if (dump_) | ||||
|         { | ||||
|             // sink_ = gr_make_file_sink(item_size_, dump_filename_.c_str()); | ||||
|             sink_ = gr::blocks::file_sink::make(output_item_size, dump_filename_.c_str()); | ||||
|             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||
|         } | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             throttle_ = gr::blocks::throttle::make(output_item_size, sampling_frequency_); | ||||
|         } | ||||
|     DLOG(INFO) << "File source filename " << filename_; | ||||
|     DLOG(INFO) << "Samples " << samples_; | ||||
|     DLOG(INFO) << "Sampling frequency " << sampling_frequency_; | ||||
|     DLOG(INFO) << "Item type " << item_type_; | ||||
|     DLOG(INFO) << "Item size " << item_size_; | ||||
|     DLOG(INFO) << "Repeat " << repeat_; | ||||
|     DLOG(INFO) << "Dump " << dump_; | ||||
|     DLOG(INFO) << "Dump filename " << dump_filename_; | ||||
|     if (in_streams_ > 0) | ||||
|     if (in_streams > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "A signal source does not have an input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 1) | ||||
|     if (out_streams > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void TwoBitPackedFileSignalSource::connect(gr::top_block_sptr top_block) | ||||
| std::tuple<size_t, bool> TwoBitPackedFileSignalSource::itemTypeToSize() | ||||
| { | ||||
|     gr::basic_block_sptr left_block = file_source_; | ||||
|     gr::basic_block_sptr right_block = unpack_samples_; | ||||
|     auto is_complex_t = false; | ||||
|     auto item_size = size_t(sizeof(char));  // default | ||||
|  | ||||
|     top_block->connect(file_source_, 0, unpack_samples_, 0); | ||||
|     left_block = right_block; | ||||
|     if (item_type() == "byte") | ||||
|         { | ||||
|             item_size = sizeof(char); | ||||
|         } | ||||
|     else if (item_type() == "short") | ||||
|         { | ||||
|             // If we have shorts stored in little endian format, might as | ||||
|             // well read them in as bytes. | ||||
|             // TODO: this seems to make assumptions about the endianness of this machine | ||||
|             if (big_endian_items_) | ||||
|                 { | ||||
|                     item_size = sizeof(int16_t); | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     // how can this be right? the number of samples is computed based on this value | ||||
|                     item_size = sizeof(char); | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << item_type() << " unrecognized item type. Using byte."; | ||||
|         } | ||||
|  | ||||
|     // the complex-ness of the input is inferred from the output type | ||||
|     if (sample_type_ == "real") | ||||
|         { | ||||
|             is_complex_t = false; | ||||
|         } | ||||
|     else if (sample_type_ == "iq") | ||||
|         { | ||||
|             is_complex_t = true; | ||||
|         } | ||||
|     else if (sample_type_ == "qi") | ||||
|         { | ||||
|             is_complex_t = true; | ||||
|             reverse_interleaving_ = true; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: " | ||||
|                          << (is_complex_t ? (reverse_interleaving_ ? "qi" : "iq") : "real"); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     return std::make_tuple(item_size, is_complex_t); | ||||
| } | ||||
|  | ||||
| // Each sample is 2 bits; if the item_type() is char, then the size is 8/2 = 4 packets per sample | ||||
| // If the item_type() is short, then the size is 16/2 = 8 packets per sample | ||||
| double TwoBitPackedFileSignalSource::packetsPerSample() const { return item_size() / 2.0; } | ||||
| gnss_shared_ptr<gr::block> TwoBitPackedFileSignalSource::source() const { return char_to_float_; } | ||||
|  | ||||
| void TwoBitPackedFileSignalSource::create_file_source_hook() | ||||
| { | ||||
|     unpack_samples_ = make_unpack_2bit_samples(big_endian_bytes_, item_size(), | ||||
|         big_endian_items_, reverse_interleaving_); | ||||
|     DLOG(INFO) << "unpack_byte_2bit_samples(" << unpack_samples_->unique_id() << ")"; | ||||
|  | ||||
|     if (is_complex()) | ||||
|         { | ||||
|             char_to_float_ = gr::blocks::interleaved_char_to_complex::make(false); | ||||
|             DLOG(INFO) << "interleaved_char_to_complex(" << char_to_float_->unique_id() << ")"; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             char_to_float_ = gr::blocks::char_to_float::make(); | ||||
|             DLOG(INFO) << "char_to_float(" << char_to_float_->unique_id() << ")"; | ||||
|         } | ||||
| } | ||||
|  | ||||
| void TwoBitPackedFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     top_block->connect(file_source(), 0, unpack_samples_, 0); | ||||
|     DLOG(INFO) << "connected file source to unpack samples"; | ||||
|     right_block = char_to_float_; | ||||
|     top_block->connect(left_block, 0, right_block, 0); | ||||
|     left_block = right_block; | ||||
|     top_block->connect(unpack_samples_, 0, char_to_float_, 0); | ||||
|     DLOG(INFO) << "connected unpack samples to char to float"; | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             right_block = throttle_; | ||||
|             top_block->connect(left_block, 0, right_block, 0); | ||||
|             left_block = right_block; | ||||
|             DLOG(INFO) << " connected to throttle"; | ||||
|         } | ||||
|  | ||||
|     top_block->connect(left_block, 0, valve_, 0); | ||||
|     DLOG(INFO) << "connected to valve"; | ||||
|     if (dump_) | ||||
|         { | ||||
|             top_block->connect(valve_, 0, sink_, 0); | ||||
|             DLOG(INFO) << "connected valve to file sink"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| void TwoBitPackedFileSignalSource::disconnect(gr::top_block_sptr top_block) | ||||
| void TwoBitPackedFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) | ||||
| { | ||||
|     gr::basic_block_sptr left_block = file_source_; | ||||
|     gr::basic_block_sptr right_block = unpack_samples_; | ||||
|  | ||||
|     top_block->disconnect(file_source_, 0, unpack_samples_, 0); | ||||
|     left_block = right_block; | ||||
|  | ||||
|     top_block->disconnect(file_source(), 0, unpack_samples_, 0); | ||||
|     DLOG(INFO) << "disconnected file source to unpack samples"; | ||||
|     right_block = char_to_float_; | ||||
|     top_block->disconnect(left_block, 0, right_block, 0); | ||||
|     left_block = right_block; | ||||
|     top_block->disconnect(unpack_samples_, 0, char_to_float_, 0); | ||||
|     DLOG(INFO) << "disconnected unpack samples to char to float"; | ||||
|  | ||||
|     if (enable_throttle_control_) | ||||
|         { | ||||
|             right_block = throttle_; | ||||
|             top_block->disconnect(left_block, 0, right_block, 0); | ||||
|             left_block = right_block; | ||||
|             DLOG(INFO) << " disconnected to throttle"; | ||||
|         } | ||||
|  | ||||
|     top_block->disconnect(left_block, 0, valve_, 0); | ||||
|     DLOG(INFO) << "disconnected to valve"; | ||||
|     if (dump_) | ||||
|         { | ||||
|             top_block->disconnect(valve_, 0, sink_, 0); | ||||
|             DLOG(INFO) << "disconnected valve to file sink"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr TwoBitPackedFileSignalSource::get_left_block() | ||||
| { | ||||
|     LOG(WARNING) << "Left block of a signal source should not be retrieved"; | ||||
|     // return gr_block_sptr(); | ||||
|     return gr::blocks::file_source::sptr(); | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr TwoBitPackedFileSignalSource::get_right_block() | ||||
| { | ||||
|     return valve_; | ||||
| } | ||||
|   | ||||
| @@ -21,17 +21,9 @@ | ||||
| #ifndef GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H | ||||
| #define GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "file_source_base.h" | ||||
| #include "unpack_2bit_samples.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/blocks/file_source.h> | ||||
| #include <gnuradio/blocks/interleaved_char_to_complex.h> | ||||
| #include <gnuradio/blocks/throttle.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <pmt/pmt.h> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| /** \addtogroup Signal_Source | ||||
| @@ -46,7 +38,7 @@ class ConfigurationInterface; | ||||
|  * \brief Class that reads signals samples from a file | ||||
|  * and adapts it to a SignalSourceInterface | ||||
|  */ | ||||
| class TwoBitPackedFileSignalSource : public GNSSBlockInterface | ||||
| class TwoBitPackedFileSignalSource : public FileSourceBase | ||||
| { | ||||
| public: | ||||
|     TwoBitPackedFileSignalSource(const ConfigurationInterface* configuration, const std::string& role, | ||||
| @@ -54,54 +46,8 @@ public: | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue); | ||||
|  | ||||
|     ~TwoBitPackedFileSignalSource() = default; | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Two_Bit_Packed_File_Signal_Source". | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Two_Bit_Packed_File_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     inline std::string filename() const | ||||
|     { | ||||
|         return filename_; | ||||
|     } | ||||
|  | ||||
|     inline std::string item_type() const | ||||
|     { | ||||
|         return item_type_; | ||||
|     } | ||||
|  | ||||
|     inline bool repeat() const | ||||
|     { | ||||
|         return repeat_; | ||||
|     } | ||||
|  | ||||
|     inline int64_t sampling_frequency() const | ||||
|     { | ||||
|         return sampling_frequency_; | ||||
|     } | ||||
|  | ||||
|     inline uint64_t samples() const | ||||
|     { | ||||
|         return samples_; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     inline bool big_endian_items() const | ||||
|     { | ||||
|         return big_endian_items_; | ||||
| @@ -112,41 +58,27 @@ public: | ||||
|         return big_endian_bytes_; | ||||
|     } | ||||
|  | ||||
|     inline bool is_complex() const | ||||
|     { | ||||
|         return is_complex_; | ||||
|     } | ||||
|  | ||||
|     inline bool reverse_interleaving() const | ||||
|     { | ||||
|         return reverse_interleaving_; | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     std::tuple<size_t, bool> itemTypeToSize() override; | ||||
|     double packetsPerSample() const override; | ||||
|     gnss_shared_ptr<gr::block> source() const override; | ||||
|     void create_file_source_hook() override; | ||||
|     void pre_connect_hook(gr::top_block_sptr top_block) override; | ||||
|     void pre_disconnect_hook(gr::top_block_sptr top_block) override; | ||||
|  | ||||
| private: | ||||
|     gr::blocks::file_source::sptr file_source_; | ||||
|     unpack_2bit_samples_sptr unpack_samples_; | ||||
|     gr::basic_block_sptr char_to_float_; | ||||
|     gnss_shared_ptr<gr::block> valve_; | ||||
|     gr::blocks::file_sink::sptr sink_; | ||||
|     gr::blocks::throttle::sptr throttle_; | ||||
|     std::string filename_; | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|     std::string sample_type_; | ||||
|     uint64_t samples_; | ||||
|     int64_t sampling_frequency_; | ||||
|     size_t item_size_; | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|     bool big_endian_items_; | ||||
|     bool big_endian_bytes_; | ||||
|     bool is_complex_; | ||||
|     bool reverse_interleaving_; | ||||
|     bool repeat_; | ||||
|     bool dump_; | ||||
|     // Throttle control | ||||
|     bool enable_throttle_control_; | ||||
|     unpack_2bit_samples_sptr unpack_samples_; | ||||
|     gnss_shared_ptr<gr::block> char_to_float_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| #include "uhd_signal_source.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_string_literals.h" | ||||
| #include "gnss_sdr_valve.h" | ||||
| #include <glog/logging.h> | ||||
| #include <uhd/exception.hpp> | ||||
| @@ -25,10 +26,13 @@ | ||||
| #include <iostream> | ||||
| #include <utility> | ||||
|  | ||||
| using namespace std::string_literals; | ||||
|  | ||||
|  | ||||
| UhdSignalSource::UhdSignalSource(const ConfigurationInterface* configuration, | ||||
|     const std::string& role, unsigned int in_stream, unsigned int out_stream, | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) | ||||
|     Concurrent_Queue<pmt::pmt_t>* queue) | ||||
|     : SignalSourceBase(configuration, role, "UHD_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream) | ||||
| { | ||||
|     // DUMP PARAMETERS | ||||
|     const std::string empty; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
| #define GNSS_SDR_UHD_SIGNAL_SOURCE_H | ||||
|  | ||||
| #include "concurrent_queue.h" | ||||
| #include "gnss_block_interface.h" | ||||
| #include "signal_source_base.h" | ||||
| #include <gnuradio/blocks/file_sink.h> | ||||
| #include <gnuradio/hier_block2.h> | ||||
| #include <gnuradio/uhd/usrp_source.h> | ||||
| @@ -38,7 +38,7 @@ class ConfigurationInterface; | ||||
| /*! | ||||
|  * \brief This class reads samples from a UHD device (see http://code.ettus.com/redmine/ettus/projects/uhd/wiki) | ||||
|  */ | ||||
| class UhdSignalSource : public GNSSBlockInterface | ||||
| class UhdSignalSource : public SignalSourceBase | ||||
| { | ||||
| public: | ||||
|     UhdSignalSource(const ConfigurationInterface* configuration, | ||||
| @@ -47,19 +47,6 @@ public: | ||||
|  | ||||
|     ~UhdSignalSource() = default; | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "UHD_Signal_Source" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "UHD_Signal_Source"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
| @@ -89,7 +76,6 @@ private: | ||||
|     std::string item_type_; | ||||
|     std::string subdevice_; | ||||
|     std::string clock_source_; | ||||
|     std::string role_; | ||||
|  | ||||
|     double sample_rate_; | ||||
|     size_t item_size_; | ||||
|   | ||||
							
								
								
									
										65
									
								
								src/core/interfaces/signal_source_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/core/interfaces/signal_source_interface.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /*! | ||||
|  * \signal_source_interface.h | ||||
|  * \brief Header file of the interface to a signal_source GNSS block. | ||||
|  * \author Jim Melton, 2020. jim.melton(at)sncorp.com | ||||
|  * | ||||
|  * This header file contains the interface to an abstract class for | ||||
|  * signal sources. Since all its methods are virtual, this class | ||||
|  * cannot be instantiated directly, and a subclass can only be | ||||
|  * instantiated directly if all inherited pure virtual methods have | ||||
|  * been implemented by that class or a parent class. | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
|  * | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #ifndef GNSS_SDR_SIGNAL_SOURCE_INTERFACE_H | ||||
| #define GNSS_SDR_SIGNAL_SOURCE_INTERFACE_H | ||||
|  | ||||
| #include "gnss_block_interface.h" | ||||
| #include <glog/logging.h> | ||||
|  | ||||
| /** \addtogroup Core | ||||
|  * \{ */ | ||||
| /** \addtogroup GNSS_Block_Interfaces GNSS block interfaces | ||||
|  * GNSS block interfaces. | ||||
|  * \{ */ | ||||
|  | ||||
| /*! \brief This abstract class represents an interface to signal_source GNSS block. | ||||
|  * | ||||
|  * Abstract class for signal sources. Since all its methods are virtual, | ||||
|  * this class cannot be instantiated directly, and a subclass can only be | ||||
|  * instantiated directly if all inherited pure virtual methods have been | ||||
|  * implemented by that class or a parent class. | ||||
|  */ | ||||
|  | ||||
| class SignalSourceInterface : public GNSSBlockInterface | ||||
| { | ||||
| public: | ||||
|     virtual size_t getRfChannels() const = 0; | ||||
|  | ||||
| protected: | ||||
|     SignalSourceInterface() | ||||
|     { | ||||
|         VLOG(1) << "SignalSourceInterface: " << this << " ctor"; | ||||
|     } | ||||
|  | ||||
| public:  // required for polymorphic destruction | ||||
|     ~SignalSourceInterface() | ||||
|     { | ||||
|         VLOG(1) << "SignalSourceInterface: " << this << " dtor"; | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -151,6 +151,7 @@ target_link_libraries(core_receiver | ||||
|     PUBLIC | ||||
|         core_libs | ||||
|     PRIVATE | ||||
|         algorithms_libs | ||||
|         core_monitor | ||||
|         signal_source_adapters | ||||
|         data_type_adapters | ||||
| @@ -169,8 +170,6 @@ target_link_libraries(core_receiver | ||||
|         Armadillo::armadillo | ||||
| ) | ||||
|  | ||||
| target_include_directories(core_receiver PRIVATE ${CMAKE_SOURCE_DIR}/src/algorithms/libs) | ||||
|  | ||||
| if(ENABLE_ARMA_NO_DEBUG) | ||||
|     target_compile_definitions(core_receiver | ||||
|         PRIVATE -DARMA_NO_BOUND_CHECKING=1 | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -38,6 +38,7 @@ | ||||
|  | ||||
| class ConfigurationInterface; | ||||
| class GNSSBlockInterface; | ||||
| class SignalSourceInterface; | ||||
| class AcquisitionInterface; | ||||
| class TrackingInterface; | ||||
| class TelemetryDecoderInterface; | ||||
| @@ -51,7 +52,7 @@ public: | ||||
|     GNSSBlockFactory() = default; | ||||
|     ~GNSSBlockFactory() = default; | ||||
|  | ||||
|     std::unique_ptr<GNSSBlockInterface> GetSignalSource(const ConfigurationInterface* configuration, | ||||
|     std::unique_ptr<SignalSourceInterface> GetSignalSource(const ConfigurationInterface* configuration, | ||||
|         Concurrent_Queue<pmt::pmt_t>* queue, int ID = -1); | ||||
|  | ||||
|     std::unique_ptr<GNSSBlockInterface> GetSignalConditioner(const ConfigurationInterface* configuration, int ID = -1); | ||||
|   | ||||
| @@ -36,6 +36,7 @@ | ||||
| #include "gnss_satellite.h" | ||||
| #include "gnss_sdr_make_unique.h" | ||||
| #include "gnss_synchro_monitor.h" | ||||
| #include "signal_source_interface.h" | ||||
| #include <boost/lexical_cast.hpp>    // for boost::lexical_cast | ||||
| #include <boost/tokenizer.hpp>       // for boost::tokenizer | ||||
| #include <glog/logging.h>            // for LOG | ||||
| @@ -100,50 +101,19 @@ void GNSSFlowgraph::init() | ||||
|     // 1. read the number of RF front-ends available (one file_source per RF front-end) | ||||
|     sources_count_ = configuration_->property("Receiver.sources_count", 1); | ||||
|  | ||||
|     int RF_Channels = 0; | ||||
|     int signal_conditioner_ID = 0; | ||||
|  | ||||
|     if (sources_count_ > 1) | ||||
|     for (int i = 0; i < sources_count_; i++) | ||||
|         { | ||||
|             for (int i = 0; i < sources_count_; i++) | ||||
|             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) | ||||
|                 { | ||||
|                     std::cout << "Creating source " << i << '\n'; | ||||
|                     sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), i)); | ||||
|                     // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. | ||||
|                     // Include GetRFChannels in the interface to avoid read config parameters here | ||||
|                     // read the number of RF channels for each front-end | ||||
|                     RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); | ||||
|                     std::cout << "RF Channels " << RF_Channels << '\n'; | ||||
|                     for (int j = 0; j < RF_Channels; j++) | ||||
|                         { | ||||
|                             sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); | ||||
|                             signal_conditioner_ID++; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             // backwards compatibility for old config files | ||||
|             sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), -1)); | ||||
|             // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. | ||||
|             // Include GetRFChannels in the interface to avoid read config parameters here | ||||
|             // read the number of RF channels for each front-end | ||||
|             if (sig_source_.at(0) != nullptr) | ||||
|                 { | ||||
|                     RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); | ||||
|                 } | ||||
|             if (RF_Channels != 0) | ||||
|                 { | ||||
|                     for (int j = 0; j < RF_Channels; j++) | ||||
|                         { | ||||
|                             sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); | ||||
|                             signal_conditioner_ID++; | ||||
|                         } | ||||
|                 } | ||||
|             else | ||||
|                 { | ||||
|                     // old config file, single signal source and single channel, not specified | ||||
|                     sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), -1)); | ||||
|                     sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); | ||||
|                     signal_conditioner_ID++; | ||||
|                 } | ||||
|         } | ||||
|  | ||||
| @@ -721,65 +691,66 @@ int GNSSFlowgraph::disconnect_signal_sources() | ||||
|  | ||||
| int GNSSFlowgraph::connect_signal_conditioners() | ||||
| { | ||||
|     for (auto& sig : sig_conditioner_) | ||||
|     int error = 1;  // this should be bool (true) | ||||
|     try | ||||
|         { | ||||
|             try | ||||
|             for (auto& sig : sig_conditioner_) | ||||
|                 { | ||||
|                     sig->connect(top_block_); | ||||
|                 } | ||||
|             catch (const std::exception& e) | ||||
|             DLOG(INFO) << "Signal Conditioner blocks successfully connected to the top_block"; | ||||
|             error = 0;  // false | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|         { | ||||
|             LOG(ERROR) << "Can't connect signal conditioner block internally: " << e.what(); | ||||
|             top_block_->disconnect_all(); | ||||
|             std::string reported_error(e.what()); | ||||
|             if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) | ||||
|                 { | ||||
|                     std::string replace_me("copy"); | ||||
|                     size_t pos = reported_error.find(replace_me); | ||||
|                     while (pos != std::string::npos) | ||||
|                         { | ||||
|                             size_t len = replace_me.length(); | ||||
|                             reported_error.replace(pos, len, "Pass_Through"); | ||||
|                             pos = reported_error.find(replace_me, pos + 1); | ||||
|                         } | ||||
|                     help_hint_ += " * Blocks within the Signal Conditioner are connected with mismatched input/ouput item size\n"; | ||||
|                     help_hint_ += "   Reported error: " + reported_error + '\n'; | ||||
|                     help_hint_ += "   Check the Signal Conditioner documentation at https://gnss-sdr.org/docs/sp-blocks/signal-conditioner/\n"; | ||||
|                 } | ||||
|             if (std::string::npos != reported_error.find(std::string("DataTypeAdapter"))) | ||||
|                 { | ||||
|                     help_hint_ += " * The DataTypeAdapter implementation set in the configuration file does not exist\n"; | ||||
|                     help_hint_ += "   Check the DataTypeAdapter documentation at https://gnss-sdr.org/docs/sp-blocks/data-type-adapter/\n"; | ||||
|                 } | ||||
|             if (std::string::npos != reported_error.find(std::string("InputFilter"))) | ||||
|                 { | ||||
|                     LOG(ERROR) << "Can't connect signal conditioner block internally: " << e.what(); | ||||
|                     top_block_->disconnect_all(); | ||||
|                     std::string reported_error(e.what()); | ||||
|                     if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) | ||||
|                         { | ||||
|                             std::string replace_me("copy"); | ||||
|                             size_t pos = reported_error.find(replace_me); | ||||
|                             while (pos != std::string::npos) | ||||
|                                 { | ||||
|                                     size_t len = replace_me.length(); | ||||
|                                     reported_error.replace(pos, len, "Pass_Through"); | ||||
|                                     pos = reported_error.find(replace_me, pos + 1); | ||||
|                                 } | ||||
|                             help_hint_ += " * Blocks within the Signal Conditioner are connected with mismatched input/ouput item size\n"; | ||||
|                             help_hint_ += "   Reported error: " + reported_error + '\n'; | ||||
|                             help_hint_ += "   Check the Signal Conditioner documentation at https://gnss-sdr.org/docs/sp-blocks/signal-conditioner/\n"; | ||||
|                             help_hint_ += " * The configured InputFilter input/output item types are not well defined.\n"; | ||||
|                         } | ||||
|                     if (std::string::npos != reported_error.find(std::string("DataTypeAdapter"))) | ||||
|                     else | ||||
|                         { | ||||
|                             help_hint_ += " * The DataTypeAdapter implementation set in the configuration file does not exist\n"; | ||||
|                             help_hint_ += "   Check the DataTypeAdapter documentation at https://gnss-sdr.org/docs/sp-blocks/data-type-adapter/\n"; | ||||
|                             help_hint_ += " * The InputFilter implementation set in the configuration file does not exist\n"; | ||||
|                         } | ||||
|                     if (std::string::npos != reported_error.find(std::string("InputFilter"))) | ||||
|                     help_hint_ += "   Check the InputFilter documentation at https://gnss-sdr.org/docs/sp-blocks/input-filter/\n"; | ||||
|                 } | ||||
|             if (std::string::npos != reported_error.find(std::string("Resampler"))) | ||||
|                 { | ||||
|                     if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) | ||||
|                         { | ||||
|                             if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) | ||||
|                                 { | ||||
|                                     help_hint_ += " * The configured InputFilter input/output item types are not well defined.\n"; | ||||
|                                 } | ||||
|                             else | ||||
|                                 { | ||||
|                                     help_hint_ += " * The InputFilter implementation set in the configuration file does not exist\n"; | ||||
|                                 } | ||||
|                             help_hint_ += "   Check the InputFilter documentation at https://gnss-sdr.org/docs/sp-blocks/input-filter/\n"; | ||||
|                             help_hint_ += " * The configured Resampler item type is not well defined.\n"; | ||||
|                         } | ||||
|                     if (std::string::npos != reported_error.find(std::string("Resampler"))) | ||||
|                     else | ||||
|                         { | ||||
|                             if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) | ||||
|                                 { | ||||
|                                     help_hint_ += " * The configured Resampler item type is not well defined.\n"; | ||||
|                                 } | ||||
|                             else | ||||
|                                 { | ||||
|                                     help_hint_ += " * The Resampler implementation set in the configuration file does not exist\n"; | ||||
|                                 } | ||||
|                             help_hint_ += "   Check the Resampler documentation at https://gnss-sdr.org/docs/sp-blocks/resampler/\n"; | ||||
|                             help_hint_ += " * The Resampler implementation set in the configuration file does not exist\n"; | ||||
|                         } | ||||
|                     return 1; | ||||
|                     help_hint_ += "   Check the Resampler documentation at https://gnss-sdr.org/docs/sp-blocks/resampler/\n"; | ||||
|                 } | ||||
|         } | ||||
|     DLOG(INFO) << "Signal Conditioner blocks successfully connected to the top_block"; | ||||
|     return 0; | ||||
|     return error; | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -1028,42 +999,40 @@ int GNSSFlowgraph::disconnect_fpga_sample_counter() | ||||
|  | ||||
| int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() | ||||
| { | ||||
|     int RF_Channels = 0; | ||||
|     unsigned int signal_conditioner_ID = 0; | ||||
|     for (int i = 0; i < sources_count_; i++) | ||||
|         { | ||||
|             try | ||||
|                 { | ||||
|                     auto& src = sig_source_.at(i); | ||||
|  | ||||
|                     // TODO: Remove this array implementation and create generic multistream connector | ||||
|                     // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) | ||||
|                     if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") | ||||
|                     if (src->implementation() == "Raw_Array_Signal_Source") | ||||
|                         { | ||||
|                             // Multichannel Array | ||||
|                             std::cout << "ARRAY MODE\n"; | ||||
|                             for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) | ||||
|                                 { | ||||
|                                     std::cout << "connecting ch " << j << '\n'; | ||||
|                                     top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); | ||||
|                                     top_block_->connect(src->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); | ||||
|                                 } | ||||
|                         } | ||||
|                     else | ||||
|                         { | ||||
|                             // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. | ||||
|                             // Include GetRFChannels in the interface to avoid read config parameters here | ||||
|                             // read the number of RF channels for each front-end | ||||
|                             RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); | ||||
|                             auto RF_Channels = src->getRfChannels(); | ||||
|  | ||||
|                             for (int j = 0; j < RF_Channels; j++) | ||||
|                             for (auto j = 0U; j < RF_Channels; ++j) | ||||
|                                 { | ||||
|                                     // Connect the multichannel signal source to multiple signal conditioners | ||||
|                                     // GNURADIO max_streams=-1 means infinite ports! | ||||
|                                     size_t output_size = sig_source_.at(i)->item_size(); | ||||
|                                     size_t output_size = src->item_size(); | ||||
|                                     size_t input_size = sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->sizeof_stream_item(0); | ||||
|                                     // Check configuration inconsistencies | ||||
|                                     if (output_size != input_size) | ||||
|                                         { | ||||
|                                             help_hint_ += " * The Signal Source implementation " + sig_source_.at(i)->implementation() + " has an output with a "; | ||||
|                                             help_hint_ += sig_source_.at(i)->role() + ".item_size of " + std::to_string(output_size); | ||||
|                                             help_hint_ += " * The Signal Source implementation " + src->implementation() + " has an output with a "; | ||||
|                                             help_hint_ += src->role() + ".item_size of " + std::to_string(output_size); | ||||
|                                             help_hint_ += " bytes, but it is connected to the Signal Conditioner implementation "; | ||||
|                                             help_hint_ += sig_conditioner_.at(signal_conditioner_ID)->implementation() + " with input item size of " + std::to_string(input_size) + " bytes.\n"; | ||||
|                                             help_hint_ += "   Output ports must be connected to input ports with the same item size.\n"; | ||||
| @@ -1071,12 +1040,12 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() | ||||
|                                             return 1; | ||||
|                                         } | ||||
|  | ||||
|                                     if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) | ||||
|                                     if (src->get_right_block()->output_signature()->max_streams() > 1 or src->get_right_block()->output_signature()->max_streams() == -1) | ||||
|                                         { | ||||
|                                             if (sig_conditioner_.size() > signal_conditioner_ID) | ||||
|                                                 { | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; | ||||
|                                                     top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << signal_conditioner_ID; | ||||
|                                                     top_block_->connect(src->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                 } | ||||
|                                         } | ||||
|                                     else | ||||
| @@ -1084,14 +1053,14 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() | ||||
|                                             if (j == 0) | ||||
|                                                 { | ||||
|                                                     // RF_channel 0 backward compatibility with single channel sources | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; | ||||
|                                                     top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << signal_conditioner_ID; | ||||
|                                                     top_block_->connect(src->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                 } | ||||
|                                             else | ||||
|                                                 { | ||||
|                                                     // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; | ||||
|                                                     top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                     LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << signal_conditioner_ID; | ||||
|                                                     top_block_->connect(src->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                 } | ||||
|                                         } | ||||
|                                     signal_conditioner_ID++; | ||||
| @@ -1127,46 +1096,44 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() | ||||
|  | ||||
| int GNSSFlowgraph::disconnect_signal_sources_from_signal_conditioners() | ||||
| { | ||||
|     int RF_Channels = 0; | ||||
|     int signal_conditioner_ID = 0; | ||||
|     for (int i = 0; i < sources_count_; i++) | ||||
|         { | ||||
|             try | ||||
|                 { | ||||
|                     auto& src = sig_source_.at(i); | ||||
|  | ||||
|                     // TODO: Remove this array implementation and create generic multistream connector | ||||
|                     // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) | ||||
|                     if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") | ||||
|                     if (src->implementation() == "Raw_Array_Signal_Source") | ||||
|                         { | ||||
|                             // Multichannel Array | ||||
|                             for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) | ||||
|                                 { | ||||
|                                     top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); | ||||
|                                     top_block_->disconnect(src->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); | ||||
|                                 } | ||||
|                         } | ||||
|                     else | ||||
|                         { | ||||
|                             // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. | ||||
|                             // Include GetRFChannels in the interface to avoid read config parameters here | ||||
|                             // read the number of RF channels for each front-end | ||||
|                             RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); | ||||
|                             auto RF_Channels = src->getRfChannels(); | ||||
|  | ||||
|                             for (int j = 0; j < RF_Channels; j++) | ||||
|                             for (auto j = 0U; j < RF_Channels; ++j) | ||||
|                                 { | ||||
|                                     if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) | ||||
|                                     if (src->get_right_block()->output_signature()->max_streams() > 1 or src->get_right_block()->output_signature()->max_streams() == -1) | ||||
|                                         { | ||||
|                                             top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                             top_block_->disconnect(src->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                         } | ||||
|                                     else | ||||
|                                         { | ||||
|                                             if (j == 0) | ||||
|                                                 { | ||||
|                                                     // RF_channel 0 backward compatibility with single channel sources | ||||
|                                                     top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                     top_block_->disconnect(src->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                 } | ||||
|                                             else | ||||
|                                                 { | ||||
|                                                     // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) | ||||
|                                                     top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                     top_block_->disconnect(src->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); | ||||
|                                                 } | ||||
|                                         } | ||||
|                                     signal_conditioner_ID++; | ||||
|   | ||||
| @@ -53,6 +53,7 @@ class ChannelInterface; | ||||
| class ConfigurationInterface; | ||||
| class GNSSBlockInterface; | ||||
| class Gnss_Satellite; | ||||
| class SignalSourceInterface; | ||||
|  | ||||
| /*! \brief This class represents a GNSS flow graph. | ||||
|  * | ||||
| @@ -230,7 +231,7 @@ private: | ||||
|     std::shared_ptr<ConfigurationInterface> configuration_; | ||||
|     std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue_; | ||||
|  | ||||
|     std::vector<std::shared_ptr<GNSSBlockInterface>> sig_source_; | ||||
|     std::vector<std::shared_ptr<SignalSourceInterface>> sig_source_; | ||||
|     std::vector<std::shared_ptr<GNSSBlockInterface>> sig_conditioner_; | ||||
|     std::vector<std::shared_ptr<ChannelInterface>> channels_; | ||||
|     std::shared_ptr<GNSSBlockInterface> observables_; | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
| #include "in_memory_configuration.h" | ||||
| #include "observables_interface.h" | ||||
| #include "pvt_interface.h" | ||||
| #include "signal_source_interface.h" | ||||
| #include "telemetry_decoder_interface.h" | ||||
| #include "tracking_interface.h" | ||||
| #include <gtest/gtest.h> | ||||
| @@ -45,7 +46,7 @@ TEST(GNSSBlockFactoryTest, InstantiateFileSignalSource) | ||||
|     // Example of a factory as a shared_ptr | ||||
|     std::shared_ptr<GNSSBlockFactory> factory = std::make_shared<GNSSBlockFactory>(); | ||||
|     // Example of a block as a shared_ptr | ||||
|     std::shared_ptr<GNSSBlockInterface> signal_source = factory->GetSignalSource(configuration.get(), queue.get()); | ||||
|     auto signal_source = factory->GetSignalSource(configuration.get(), queue.get()); | ||||
|     EXPECT_STREQ("SignalSource", signal_source->role().c_str()); | ||||
|     EXPECT_STREQ("File_Signal_Source", signal_source->implementation().c_str()); | ||||
| } | ||||
| @@ -59,7 +60,7 @@ TEST(GNSSBlockFactoryTest, InstantiateWrongSignalSource) | ||||
|     // Example of a factory as a unique_ptr | ||||
|     std::unique_ptr<GNSSBlockFactory> factory = std::make_unique<GNSSBlockFactory>(); | ||||
|     // Example of a block as a unique_ptr | ||||
|     std::unique_ptr<GNSSBlockInterface> signal_source = factory->GetSignalSource(configuration.get(), queue.get()); | ||||
|     auto signal_source = factory->GetSignalSource(configuration.get(), queue.get()); | ||||
|     EXPECT_EQ(nullptr, signal_source); | ||||
| } | ||||
|  | ||||
| @@ -350,8 +351,8 @@ TEST(GNSSBlockFactoryTest, InstantiateWrongPvt) | ||||
| { | ||||
|     std::shared_ptr<InMemoryConfiguration> configuration = std::make_shared<InMemoryConfiguration>(); | ||||
|     configuration->set_property("PVT.implementation", "Pepito"); | ||||
|     std::unique_ptr<GNSSBlockFactory> factory = std::make_unique<GNSSBlockFactory>(); | ||||
|     auto factory = std::make_unique<GNSSBlockFactory>(); | ||||
|     std::shared_ptr<GNSSBlockInterface> pvt_ = factory->GetPVT(configuration.get()); | ||||
|     std::shared_ptr<PvtInterface> pvt = std::dynamic_pointer_cast<PvtInterface>(pvt_); | ||||
|     auto pvt = std::dynamic_pointer_cast<PvtInterface>(pvt_); | ||||
|     EXPECT_EQ(nullptr, pvt); | ||||
| } | ||||
|   | ||||
| @@ -53,5 +53,9 @@ TEST(FileSignalSource, InstantiateFileNotExists) | ||||
|     config->set_property("Test.item_type", "gr_complex"); | ||||
|     config->set_property("Test.repeat", "false"); | ||||
|  | ||||
|     EXPECT_THROW({ auto uptr = std::make_shared<FileSignalSource>(config.get(), "Test", 0, 1, queue.get()); }, std::exception); | ||||
|     // the file existence test was moved from the ctor to the connect() call. The argument to | ||||
|     // connect doesn't matter, since the exception should be thrown sooner than any connections | ||||
|     auto top = gr::make_top_block("GNSSUnitTest"); | ||||
|     auto uptr = std::make_shared<FileSignalSource>(config.get(), "Test", 0, 1, queue.get()); | ||||
|     EXPECT_THROW({ uptr->connect(top); }, std::exception); | ||||
| } | ||||
|   | ||||
| @@ -36,7 +36,8 @@ | ||||
| #include "gps_iono.h" | ||||
| #include "gps_l1_ca_pcps_acquisition_fine_doppler.h" | ||||
| #include "gps_utc_model.h" | ||||
| #include <boost/any.hpp>  // for bad_any_cast | ||||
| #include "signal_source_interface.h"  // for SignalSourceInterface | ||||
| #include <boost/any.hpp>              // for bad_any_cast | ||||
| #include <boost/exception/exception.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <gflags/gflags.h> | ||||
| @@ -181,6 +182,10 @@ void wait_message() | ||||
|  | ||||
| bool front_end_capture(const std::shared_ptr<ConfigurationInterface>& configuration) | ||||
| { | ||||
|     auto success = false; | ||||
|  | ||||
|     std::string trace_step; | ||||
|  | ||||
|     gr::top_block_sptr top_block; | ||||
|     GNSSBlockFactory block_factory; | ||||
|     std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue; | ||||
| @@ -188,43 +193,37 @@ bool front_end_capture(const std::shared_ptr<ConfigurationInterface>& configurat | ||||
|     queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>(); | ||||
|     top_block = gr::make_top_block("Acquisition test"); | ||||
|  | ||||
|     std::shared_ptr<GNSSBlockInterface> source; | ||||
|     try | ||||
|         { | ||||
|             // Note: the block_factory returns a unique_ptr (what you would get with an "auto" | ||||
|             // declaration), but the flowgraph uses shared_ptr. Without further understanding of why | ||||
|             // it should matter in this context, used shared_ptr throughout | ||||
|             std::shared_ptr<SignalSourceInterface> source; | ||||
|             std::shared_ptr<GNSSBlockInterface> conditioner; | ||||
|  | ||||
|             trace_step = "creating source"; | ||||
|             source = block_factory.GetSignalSource(configuration.get(), queue.get()); | ||||
|         } | ||||
|     catch (const boost::exception_ptr& e) | ||||
|         { | ||||
|             std::cout << "Exception caught in creating source " << e << '\n'; | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|     std::shared_ptr<GNSSBlockInterface> conditioner; | ||||
|     try | ||||
|         { | ||||
|             trace_step = "creating signal conditioner"; | ||||
|             conditioner = block_factory.GetSignalConditioner(configuration.get()); | ||||
|         } | ||||
|     catch (const boost::exception_ptr& e) | ||||
|         { | ||||
|             std::cout << "Exception caught in creating signal conditioner " << e << '\n'; | ||||
|             return false; | ||||
|         } | ||||
|     gr::block_sptr sink; | ||||
|     sink = gr::blocks::file_sink::make(sizeof(gr_complex), "tmp_capture.dat"); | ||||
|  | ||||
|     // -- Find number of samples per spreading code --- | ||||
|     int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000); | ||||
|     int samples_per_code = round(fs_in_ / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS)); | ||||
|     int nsamples = samples_per_code * 50; | ||||
|             trace_step = "unexpected in setup code"; | ||||
|  | ||||
|     int skip_samples = fs_in_ * 5;  // skip 5 seconds | ||||
|             gr::block_sptr sink; | ||||
|             sink = gr::blocks::file_sink::make(sizeof(gr_complex), "tmp_capture.dat"); | ||||
|  | ||||
|     gr::block_sptr head = gr::blocks::head::make(sizeof(gr_complex), nsamples); | ||||
|             // -- Find number of samples per spreading code --- | ||||
|             int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000); | ||||
|             int samples_per_code = round(fs_in_ / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS)); | ||||
|             int nsamples = samples_per_code * 50; | ||||
|  | ||||
|     gr::block_sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), skip_samples); | ||||
|             int skip_samples = fs_in_ * 5;  // skip 5 seconds | ||||
|  | ||||
|     try | ||||
|         { | ||||
|             gr::block_sptr head = gr::blocks::head::make(sizeof(gr_complex), nsamples); | ||||
|  | ||||
|             gr::block_sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), skip_samples); | ||||
|  | ||||
|             trace_step = "connecting the GNU Radio blocks"; | ||||
|             source->connect(top_block); | ||||
|             conditioner->connect(top_block); | ||||
|             top_block->connect(source->get_right_block(), 0, conditioner->get_left_block(), 0); | ||||
| @@ -232,14 +231,15 @@ bool front_end_capture(const std::shared_ptr<ConfigurationInterface>& configurat | ||||
|             top_block->connect(skiphead, 0, head, 0); | ||||
|             top_block->connect(head, 0, sink, 0); | ||||
|             top_block->run(); | ||||
|  | ||||
|             success = true; | ||||
|         } | ||||
|     catch (const std::exception& e) | ||||
|     catch (std::exception const& e) | ||||
|         { | ||||
|             std::cout << "Failure connecting the GNU Radio blocks " << e.what() << '\n'; | ||||
|             return false; | ||||
|             std::cout << "Exception caught " << trace_step << ": " << e.what() << std::endl; | ||||
|         } | ||||
|  | ||||
|     return true; | ||||
|     return success; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez