mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-29 22:42:59 +00:00 
			
		
		
		
	initial implementation of common file source base class
Only the file_signal_source uses it at this time; changing multi-channel to use it can be done with a little work
This commit is contained in:
		| @@ -93,6 +93,7 @@ endif() | |||||||
|  |  | ||||||
| set(SIGNAL_SOURCE_ADAPTER_SOURCES | set(SIGNAL_SOURCE_ADAPTER_SOURCES | ||||||
|     signal_source_base.cc |     signal_source_base.cc | ||||||
|  |     file_source_base.cc | ||||||
|     file_signal_source.cc |     file_signal_source.cc | ||||||
|     multichannel_file_signal_source.cc |     multichannel_file_signal_source.cc | ||||||
|     gen_signal_source.cc |     gen_signal_source.cc | ||||||
| @@ -108,6 +109,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES | |||||||
|  |  | ||||||
| set(SIGNAL_SOURCE_ADAPTER_HEADERS | set(SIGNAL_SOURCE_ADAPTER_HEADERS | ||||||
|     signal_source_base.h |     signal_source_base.h | ||||||
|  |     file_source_base.h | ||||||
|     file_signal_source.h |     file_signal_source.h | ||||||
|     multichannel_file_signal_source.h |     multichannel_file_signal_source.h | ||||||
|     gen_signal_source.h |     gen_signal_source.h | ||||||
| @@ -170,6 +172,18 @@ if(GNURADIO_USES_STD_POINTERS) | |||||||
|     ) |     ) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | # This should really be at a higher level and apply universally to the | ||||||
|  | # build system | ||||||
|  | if(FILESYSTEM_FOUND) | ||||||
|  |     target_compile_definitions(signal_source_adapters PUBLIC -DHAS_STD_FILESYSTEM=1) | ||||||
|  |     if(find_experimental) | ||||||
|  |         target_compile_definitions(signal_source_adapters PUBLIC -DHAS_STD_FILESYSTEM_EXPERIMENTAL=1) | ||||||
|  |     endif() | ||||||
|  |     target_link_libraries(signal_source_adapters PUBLIC std::filesystem) | ||||||
|  | else() | ||||||
|  |     target_link_libraries(signal_source_adapters PUBLIC Boost::filesystem Boost::system) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(ENABLE_RAW_UDP AND PCAP_FOUND) | if(ENABLE_RAW_UDP AND PCAP_FOUND) | ||||||
|     target_link_libraries(signal_source_adapters |     target_link_libraries(signal_source_adapters | ||||||
|         PRIVATE |         PRIVATE | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ | |||||||
| #include "file_signal_source.h" | #include "file_signal_source.h" | ||||||
| #include "configuration_interface.h" | #include "configuration_interface.h" | ||||||
| #include "gnss_sdr_flags.h" | #include "gnss_sdr_flags.h" | ||||||
| #include "gnss_sdr_valve.h" |  | ||||||
| #include <glog/logging.h> | #include <glog/logging.h> | ||||||
| #include <exception> | #include <exception> | ||||||
| #include <fstream> | #include <fstream> | ||||||
| @@ -32,324 +31,16 @@ using namespace std::string_literals; | |||||||
| FileSignalSource::FileSignalSource(ConfigurationInterface const* configuration, | FileSignalSource::FileSignalSource(ConfigurationInterface const* configuration, | ||||||
|     std::string const& role, unsigned int in_streams, unsigned int out_streams, |     std::string const& role, unsigned int in_streams, unsigned int out_streams, | ||||||
|     Concurrent_Queue<pmt::pmt_t>* queue) |     Concurrent_Queue<pmt::pmt_t>* queue) | ||||||
|   : SignalSourceBase(configuration, role, "File_Signal_Source"s) |   : FileSourceBase(configuration, role, "File_Signal_Source"s, queue) | ||||||
| , in_streams_(in_streams), out_streams_(out_streams) |  | ||||||
| { | { | ||||||
|     const std::string default_filename("./example_capture.dat"); |     if (in_streams > 0) | ||||||
|     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) |  | ||||||
|         { |         { | ||||||
|             LOG(ERROR) << "A signal source does not have an input stream"; |             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"; |             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,7 +21,7 @@ | |||||||
| #ifndef GNSS_SDR_FILE_SIGNAL_SOURCE_H | #ifndef GNSS_SDR_FILE_SIGNAL_SOURCE_H | ||||||
| #define GNSS_SDR_FILE_SIGNAL_SOURCE_H | #define GNSS_SDR_FILE_SIGNAL_SOURCE_H | ||||||
|  |  | ||||||
| #include "signal_source_base.h" | #include "file_source_base.h" | ||||||
|  |  | ||||||
| #include "concurrent_queue.h" | #include "concurrent_queue.h" | ||||||
| #include <gnuradio/blocks/file_sink.h> | #include <gnuradio/blocks/file_sink.h> | ||||||
| @@ -46,7 +46,7 @@ class ConfigurationInterface; | |||||||
|  * \brief Class that reads signals samples from a file |  * \brief Class that reads signals samples from a file | ||||||
|  * and adapts it to a SignalSourceInterface |  * and adapts it to a SignalSourceInterface | ||||||
|  */ |  */ | ||||||
| class FileSignalSource : public SignalSourceBase | class FileSignalSource : public FileSourceBase | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     FileSignalSource(ConfigurationInterface const* configuration, std::string const& role, |     FileSignalSource(ConfigurationInterface const* configuration, std::string const& role, | ||||||
| @@ -55,61 +55,7 @@ public: | |||||||
|  |  | ||||||
|     ~FileSignalSource() = default; |     ~FileSignalSource() = default; | ||||||
|  |  | ||||||
|     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: | 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 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_; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										396
									
								
								src/algorithms/signal_source/adapters/file_source_base.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										396
									
								
								src/algorithms/signal_source/adapters/file_source_base.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,396 @@ | |||||||
|  | /*! | ||||||
|  |  * \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_flags.h" | ||||||
|  | #include "gnss_sdr_filesystem.h" | ||||||
|  | #include "gnss_sdr_valve.h" | ||||||
|  | #include <glog/logging.h> | ||||||
|  | #include <fstream> | ||||||
|  | #include <cmath>		// ceil, floor | ||||||
|  |  | ||||||
|  |  | ||||||
|  | using namespace std::string_literals; | ||||||
|  |  | ||||||
|  | void FileSourceBase::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |   init(); | ||||||
|  |  | ||||||
|  |     auto source = gr::basic_block_sptr(); | ||||||
|  |     auto output = gr::basic_block_sptr(); | ||||||
|  |  | ||||||
|  |     // THROTTLE | ||||||
|  |     if (enable_throttle_control_) | ||||||
|  |         { | ||||||
|  |             // if we are throttling... | ||||||
|  |             throttle_ = gr::blocks::throttle::make(item_size_, sampling_frequency_); | ||||||
|  |  | ||||||
|  |             top_block->connect(file_source_, 0, throttle_, 0); | ||||||
|  |             DLOG(INFO) << "connected file source to throttle"; | ||||||
|  |  | ||||||
|  |             source = throttle_; | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             // no throttle; let 'er rip | ||||||
|  |             source = file_source_; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // 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(item_size_, samples_, queue_); | ||||||
|  |             DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; | ||||||
|  |  | ||||||
|  |             top_block->connect(source, 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=source" | ||||||
|  |             output = file_source_; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // DUMP | ||||||
|  |     if (dump_) | ||||||
|  |         { | ||||||
|  |             sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); | ||||||
|  |             DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; | ||||||
|  |  | ||||||
|  |             top_block->connect(output, 0, sink_, 0); | ||||||
|  |             DLOG(INFO) << "connected output to file sink"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void FileSourceBase::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 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() | ||||||
|  | { | ||||||
|  |     if (samples_ > 0) | ||||||
|  |         { | ||||||
|  |             return valve_; | ||||||
|  |         } | ||||||
|  |     if (enable_throttle_control_ == true) | ||||||
|  |         { | ||||||
|  |             return throttle_; | ||||||
|  |         } | ||||||
|  |     return file_source_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void FileSourceBase::init() | ||||||
|  | { | ||||||
|  |     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() << ")"; | ||||||
|  |  | ||||||
|  |     // 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_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std::string role, std::string impl, | ||||||
|  |         Concurrent_Queue<pmt::pmt_t>* queue) | ||||||
|  |     : SignalSourceBase(configuration, role, impl) | ||||||
|  |     , filename_(configuration->property(role + ".filename"s, "../data/example_capture.dat"s)) | ||||||
|  |     , file_source_() | ||||||
|  |  | ||||||
|  |     , item_type_(configuration->property(role + ".item_type"s, "short"s)) | ||||||
|  |     , item_size_(0)		// invalid | ||||||
|  |     , is_complex_(false) | ||||||
|  |  | ||||||
|  |     , header_size_(configuration->property(role + ".header_size"s, 0UL)) | ||||||
|  |     , seconds_to_skip_(configuration->property(role + ".seconds_to_skip", 0.0)) | ||||||
|  |     , repeat_(configuration->property(role + ".repeat"s, false)) | ||||||
|  |  | ||||||
|  |     , samples_(configuration->property(role + ".samples"s, 0UL)) | ||||||
|  |     , sampling_frequency_(configuration->property(role + ".sampling_frequency"s, 0UL)) | ||||||
|  |     , valve_() | ||||||
|  |     , queue_(queue) | ||||||
|  |        | ||||||
|  |     , enable_throttle_control_(configuration->property(role + ".enable_throttle_control"s, false)) | ||||||
|  |     , throttle_() | ||||||
|  |        | ||||||
|  |     , dump_(configuration->property(role + ".dump"s, false)) | ||||||
|  |     , dump_filename_(configuration->property(role + ".dump_filename"s, "../data/my_capture.dat"s)) | ||||||
|  |     , sink_() | ||||||
|  | { | ||||||
|  |     // override value with commandline flag, if present | ||||||
|  |     if (FLAGS_signal_source != "-") | ||||||
|  |         { | ||||||
|  |             filename_ = FLAGS_signal_source; | ||||||
|  |         } | ||||||
|  |     if (FLAGS_s != "-") | ||||||
|  |         { | ||||||
|  |             filename_ = FLAGS_s; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::tuple<size_t, bool> FileSourceBase::itemTypeToSize() const | ||||||
|  | { | ||||||
|  |     auto is_complex = 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 = 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); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     return std::make_tuple(item_size, is_complex); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t FileSourceBase::samplesToSkip() const | ||||||
|  | { | ||||||
|  |     auto samples_to_skip = size_t(0); | ||||||
|  |  | ||||||
|  |     if (seconds_to_skip_ > 0) | ||||||
|  |         { | ||||||
|  |             samples_to_skip = static_cast<size_t>(seconds_to_skip_ * sampling_frequency_); | ||||||
|  |  | ||||||
|  |             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()); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // this could throw, but the existence of the file has been proven before we get here. | ||||||
|  |     auto size = fs::file_size(filename()); | ||||||
|  |     n_samples = std::floor(1.0 * 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; | ||||||
|  | } | ||||||
							
								
								
									
										139
									
								
								src/algorithms/signal_source/adapters/file_source_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/algorithms/signal_source/adapters/file_source_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | /*! | ||||||
|  |  * \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 "signal_source_base.h" | ||||||
|  |  | ||||||
|  | #include "concurrent_queue.h" | ||||||
|  | #include <pmt/pmt.h> | ||||||
|  | #include <gnuradio/blocks/file_source.h> | ||||||
|  | #include <gnuradio/blocks/throttle.h> | ||||||
|  |  | ||||||
|  | // for dump | ||||||
|  | #include <gnuradio/blocks/file_sink.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include <cstddef> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ConfigurationInterface; | ||||||
|  |  | ||||||
|  | // 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; | ||||||
|  |  | ||||||
|  |     //! perform post-construction initialization | ||||||
|  |     void init(); | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     //! Constructor | ||||||
|  |     FileSourceBase(ConfigurationInterface const* configuration, std::string role, std::string impl, | ||||||
|  |         Concurrent_Queue<pmt::pmt_t>* queue); | ||||||
|  |  | ||||||
|  |     //! 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() 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; | ||||||
|  |      | ||||||
|  | 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_; | ||||||
|  |     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 | ||||||
| @@ -6,13 +6,10 @@ | |||||||
|  * |  * | ||||||
|  * ----------------------------------------------------------------------------- |  * ----------------------------------------------------------------------------- | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  * |  | ||||||
|  * GNSS-SDR is a software defined Global Navigation |  | ||||||
|  *          Satellite Systems receiver |  | ||||||
|  * |  | ||||||
|  * This file is 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 |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  * |  * | ||||||
|  * ----------------------------------------------------------------------------- |  * ----------------------------------------------------------------------------- | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jim Melton
					Jim Melton