diff --git a/CMakeLists.txt b/CMakeLists.txt index e3a44189f..dec1a3edb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -702,14 +702,25 @@ if(NOT ${FILESYSTEM_FOUND}) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem) endif() find_package(Boost ${GNSSSDR_BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED) + +if(NOT Boost_FOUND) + message(FATAL_ERROR "Fatal error: Boost (version >=${GNSSSDR_BOOST_MIN_VERSION}) required.") +endif() + set_package_properties(Boost PROPERTIES URL "https://www.boost.org" - DESCRIPTION "Portable C++ source libraries" PURPOSE "Used widely across the source code." TYPE REQUIRED ) -if(NOT Boost_FOUND) - message(FATAL_ERROR "Fatal error: Boost (version >=${GNSSSDR_BOOST_MIN_VERSION}) required.") + +if(CMAKE_VERSION VERSION_GREATER 3.14) + set_package_properties(Boost PROPERTIES + DESCRIPTION "Portable C++ source libraries (found: ${Boost_VERSION_STRING})" + ) +else() + set_package_properties(Boost PROPERTIES + DESCRIPTION "Portable C++ source libraries (found: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION})" + ) endif() if(CMAKE_VERSION VERSION_LESS 3.5) @@ -1669,6 +1680,10 @@ if(NOT MATIO_FOUND OR MATIO_VERSION_STRING VERSION_LESS ${GNSSSDR_MATIO_MIN_VERS set_package_properties(MATIO PROPERTIES PURPOSE "Matio v${GNSSSDR_MATIO_LOCAL_VERSION} will be downloaded and built when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'." ) +else() + set_package_properties(MATIO PROPERTIES + DESCRIPTION "MATLAB MAT File I/O Library (found: v.${MATIO_VERSION_STRING})" + ) endif() @@ -1796,6 +1811,13 @@ if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9) set(Protobuf_VERSION "${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}") endif() endif() + +if(Protobuf_FOUND) + set_package_properties(Protobuf PROPERTIES + DESCRIPTION "Structured data serialization mechanism (found: v${Protobuf_VERSION})" + ) +endif() + if(Protobuf_FOUND AND CMAKE_CROSSCOMPILING) find_program(PROTOC_EXECUTABLE protoc) if(NOT PROTOC_EXECUTABLE) @@ -1815,6 +1837,7 @@ if(Protobuf_FOUND AND CMAKE_CROSSCOMPILING) message(FATAL_ERROR "Please install the Protocol Buffers compiler v${Protobuf_VERSION} in the host machine") endif() endif() + if((NOT Protobuf_FOUND) OR (NOT Protobuf_PROTOC_EXECUTABLE) OR (${Protobuf_VERSION} VERSION_LESS ${GNSSSDR_PROTOBUF_MIN_VERSION})) unset(Protobuf_PROTOC_EXECUTABLE) if(CMAKE_CROSSCOMPILING) diff --git a/cmake/Modules/FindLOG4CPP.cmake b/cmake/Modules/FindLOG4CPP.cmake index 784d1f2d0..83d6532ac 100644 --- a/cmake/Modules/FindLOG4CPP.cmake +++ b/cmake/Modules/FindLOG4CPP.cmake @@ -85,7 +85,6 @@ find_library(LOG4CPP_LIBRARY /usr/lib/alpha-linux-gnu /usr/lib64 /usr/lib - /usr/local/lib /opt/local/lib ${LOG4CPP_ROOT}/lib $ENV{LOG4CPP_ROOT}/lib diff --git a/docs/changelog b/docs/changelog index 25156e270..3b8c0438e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -64,8 +64,9 @@ - The receiver now admits FPGA off-loading, allowing for real time operation at high sampling rates and higher number of signals and channels. - Fixed program termination (avoiding hangs and segfaults in some platforms/configurations). - The Labsat_Signal_Source now terminates the receiver's execution when the end of file(s) is reached. It now accepts LabSat 2 filenames and series of LabSat 3 files. -- CMake now generates a summary of enabled/disabled features. This info is also stored in a file called features.log in the building directory. +- Added configuration parameters to set the annotation rate in KML, GPX, GeoJSON and NMEA outputs, set by default to 1 s. - New parameter PVT.show_local_time_zone displays time in the local time zone. Subject to the proper system configuration of the machine running the software receiver. +- CMake now generates a summary of enabled/disabled features. This info is also stored in a file called features.log in the building directory. - Improved information provided to the user in case of failure. diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index cae7fc052..51579ad06 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -138,6 +138,11 @@ Rtklib_Pvt::Rtklib_Pvt(ConfigurationInterface* configuration, pvt_output_parameters.rtcm_msg_rate_ms[k] = rtcm_MT1097_rate_ms; } + pvt_output_parameters.kml_rate_ms = bc::lcm(configuration->property(role + ".kml_rate_ms", pvt_output_parameters.kml_rate_ms), pvt_output_parameters.output_rate_ms); + pvt_output_parameters.gpx_rate_ms = bc::lcm(configuration->property(role + ".gpx_rate_ms", pvt_output_parameters.gpx_rate_ms), pvt_output_parameters.output_rate_ms); + pvt_output_parameters.geojson_rate_ms = bc::lcm(configuration->property(role + ".geojson_rate_ms", pvt_output_parameters.geojson_rate_ms), pvt_output_parameters.output_rate_ms); + pvt_output_parameters.nmea_rate_ms = bc::lcm(configuration->property(role + ".nmea_rate_ms", pvt_output_parameters.nmea_rate_ms), pvt_output_parameters.output_rate_ms); + // Infer the type of receiver /* * TYPE | RECEIVER diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 2af4082b6..199ce7d04 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -178,6 +178,11 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, std::string kml_dump_filename; kml_dump_filename = d_dump_filename; d_kml_output_enabled = conf_.kml_output_enabled; + d_kml_rate_ms = conf_.kml_rate_ms; + if (d_kml_rate_ms == 0) + { + d_kml_output_enabled = false; + } if (d_kml_output_enabled) { d_kml_dump = std::make_shared(conf_.kml_output_path); @@ -192,6 +197,11 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, std::string gpx_dump_filename; gpx_dump_filename = d_dump_filename; d_gpx_output_enabled = conf_.gpx_output_enabled; + d_gpx_rate_ms = conf_.gpx_rate_ms; + if (d_gpx_rate_ms == 0) + { + d_gpx_output_enabled = false; + } if (d_gpx_output_enabled) { d_gpx_dump = std::make_shared(conf_.gpx_output_path); @@ -206,6 +216,11 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, std::string geojson_dump_filename; geojson_dump_filename = d_dump_filename; d_geojson_output_enabled = conf_.geojson_output_enabled; + d_geojson_rate_ms = conf_.geojson_rate_ms; + if (d_geojson_rate_ms == 0) + { + d_geojson_output_enabled = false; + } if (d_geojson_output_enabled) { d_geojson_printer = std::make_shared(conf_.geojson_output_path); @@ -218,6 +233,12 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, // initialize nmea_printer d_nmea_output_file_enabled = (conf_.nmea_output_file_enabled or conf_.flag_nmea_tty_port); + d_nmea_rate_ms = conf_.nmea_rate_ms; + if (d_nmea_rate_ms == 0) + { + d_nmea_output_file_enabled = false; + } + if (d_nmea_output_file_enabled) { d_nmea_printer = std::make_shared(conf_.nmea_dump_filename, conf_.nmea_output_file_enabled, conf_.flag_nmea_tty_port, conf_.nmea_dump_devname, conf_.nmea_output_file_path); @@ -1799,19 +1820,31 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } if (d_kml_output_enabled) { - d_kml_dump->print_position(d_pvt_solver, false); + if (current_RX_time_ms % d_kml_rate_ms == 0) + { + d_kml_dump->print_position(d_pvt_solver, false); + } } if (d_gpx_output_enabled) { - d_gpx_dump->print_position(d_pvt_solver, false); + if (current_RX_time_ms % d_gpx_rate_ms == 0) + { + d_gpx_dump->print_position(d_pvt_solver, false); + } } if (d_geojson_output_enabled) { - d_geojson_printer->print_position(d_pvt_solver, false); + if (current_RX_time_ms % d_geojson_rate_ms == 0) + { + d_geojson_printer->print_position(d_pvt_solver, false); + } } if (d_nmea_output_file_enabled) { - d_nmea_printer->Print_Nmea_Line(d_pvt_solver, false); + if (current_RX_time_ms % d_nmea_rate_ms == 0) + { + d_nmea_printer->Print_Nmea_Line(d_pvt_solver, false); + } } /* diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index a97874da8..ade48e8b7 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -106,6 +106,11 @@ private: int32_t d_rtcm_MT1097_rate_ms; // Galileo MSM7. The type 7 Multiple Signal Message format for Europe’s Galileo system int32_t d_rtcm_MSM_rate_ms; + int32_t d_kml_rate_ms; + int32_t d_gpx_rate_ms; + int32_t d_geojson_rate_ms; + int32_t d_nmea_rate_ms; + int32_t d_last_status_print_seg; // for status printer uint32_t d_nchannels; diff --git a/src/algorithms/PVT/libs/pvt_conf.cc b/src/algorithms/PVT/libs/pvt_conf.cc index 990745632..d16db0526 100644 --- a/src/algorithms/PVT/libs/pvt_conf.cc +++ b/src/algorithms/PVT/libs/pvt_conf.cc @@ -35,6 +35,10 @@ Pvt_Conf::Pvt_Conf() type_of_receiver = 0U; output_rate_ms = 0; display_rate_ms = 0; + kml_rate_ms = 1000; + gpx_rate_ms = 1000; + geojson_rate_ms = 1000; + nmea_rate_ms = 1000; rinex_version = 0; rinexobs_rate_ms = 0; diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index 7d6b02f89..1b6897e7e 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -41,6 +41,10 @@ public: uint32_t type_of_receiver; int32_t output_rate_ms; int32_t display_rate_ms; + int32_t kml_rate_ms; + int32_t gpx_rate_ms; + int32_t geojson_rate_ms; + int32_t nmea_rate_ms; int32_t rinex_version; int32_t rinexobs_rate_ms; diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index ba3cd23b0..e9cba3c93 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -129,6 +129,7 @@ endif() set(SIGNAL_SOURCE_ADAPTER_SOURCES file_signal_source.cc + multichannel_file_signal_source.cc gen_signal_source.cc nsr_file_signal_source.cc spir_file_signal_source.cc @@ -142,6 +143,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES set(SIGNAL_SOURCE_ADAPTER_HEADERS file_signal_source.h + multichannel_file_signal_source.h gen_signal_source.h nsr_file_signal_source.h spir_file_signal_source.h diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc new file mode 100644 index 000000000..28e992dbe --- /dev/null +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc @@ -0,0 +1,311 @@ +/*! + * \file multichannel_file_signal_source.cc + * \brief Implementation of a class that reads signals samples from files at + * different frequency band and adapts it to a SignalSourceInterface + * \author Javier Arribas, 2019 jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "multichannel_file_signal_source.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include +#include // for std::cerr +#include + + +MultichannelFileSignalSource::MultichannelFileSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) +{ + std::string default_filename = "./example_capture.dat"; + std::string default_item_type = "short"; + std::string default_dump_filename = "./my_capture.dat"; + + double default_seconds_to_skip = 0.0; + size_t header_size = 0; + samples_ = configuration->property(role + ".samples", 0); + sampling_frequency_ = configuration->property(role + ".sampling_frequency", 0); + n_channels_ = configuration->property(role + ".total_channels", 1); + + for (unsigned int n = 0; n < n_channels_; n++) + { + filename_vec_.push_back(configuration->property(role + ".filename" + std::to_string(n), default_filename)); + } + + item_type_ = configuration->property(role + ".item_type", default_item_type); + repeat_ = configuration->property(role + ".repeat", false); + enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); + + double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); + 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 + { + for (unsigned int n = 0; n < n_channels_; n++) + { + file_source_vec_.push_back(gr::blocks::file_source::make(item_size_, filename_vec_.at(n).c_str(), repeat_)); + + if (seconds_to_skip > 0) + { + samples_to_skip = static_cast(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 #" << n; + if (not file_source_vec_.back()->seek(samples_to_skip, SEEK_SET)) + { + LOG(INFO) << "Error skipping bytes!"; + } + } + } + } + catch (const std::exception& e) + { + if (filename_vec_.at(0) == default_filename) + { + std::cerr + << "The configuration file has not been found." + << std::endl + << "Please create a configuration file based on the examples at the 'conf/' folder " + << std::endl + << "and then generate your own GNSS Software Defined Receiver by doing:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl; + } + else + { + std::cerr + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; + } + + LOG(INFO) << "file_signal_source: Unable to open the samples file " + << filename_vec_.at(0).c_str() << ", exiting the program."; + throw(e); + } + + //todo from here.... add mux demux also + 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_vec_.at(0).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(size) / static_cast(item_size())); + } + else + { + std::cout << "file_signal_source: Unable to open the samples file " << filename_vec_.at(0).c_str() << std::endl; + LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_vec_.at(0).c_str(); + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename_vec_.at(0) << ", which contains " << static_cast(size) << " [bytes]" << std::endl; + std::cout.precision(ss); + + if (size > 0) + { + int64_t bytes_to_skip = samples_to_skip * item_size_; + int64_t bytes_to_process = static_cast(size) - bytes_to_skip; + samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size()) - ceil(0.002 * static_cast(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; + signal_duration_s = static_cast(samples_) * (1 / static_cast(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]" << std::endl; + + valve_ = gnss_sdr_make_valve(item_size_, samples_ * n_channels_, queue_); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + + if (enable_throttle_control_) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + throttle_vec_.push_back(gr::blocks::throttle::make(item_size_, sampling_frequency_)); + } + } + + for (unsigned int n = 0; n < n_channels_; n++) + { + LOG(INFO) << "Multichanne File source filename #" << n << filename_vec_.at(n); + } + + 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_; + + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +MultichannelFileSignalSource::~MultichannelFileSignalSource() = default; + + +void MultichannelFileSignalSource::connect(gr::top_block_sptr top_block) +{ + if (enable_throttle_control_ == true) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->connect(file_source_vec_.at(n), 0, throttle_vec_.at(n), 0); + DLOG(INFO) << "connected file_source #" << n << " to throttle"; + top_block->connect(throttle_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "connected throttle #" << n << " to valve_"; + } + } + else + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->connect(file_source_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "connected file_source #" << n << " to valve_"; + } + } +} + + +void MultichannelFileSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (enable_throttle_control_ == true) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->disconnect(file_source_vec_.at(n), 0, throttle_vec_.at(n), 0); + DLOG(INFO) << "disconnected file_source #" << n << " to throttle"; + top_block->disconnect(throttle_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "disconnected throttle #" << n << " to valve_"; + } + } + else + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->disconnect(file_source_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "disconnected file_source #" << n << " to valve_"; + } + } +} + + +gr::basic_block_sptr MultichannelFileSignalSource::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 MultichannelFileSignalSource::get_right_block() +{ + return valve_; +} diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h new file mode 100644 index 000000000..b248073dd --- /dev/null +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h @@ -0,0 +1,131 @@ +/*! + * \file multichannel_file_signal_source.h + * \brief Implementation of a class that reads signals samples from files at + * different frequency band and adapts it to a SignalSourceInterface + * \author Javier Arribas, 2019 jarribas(at)cttc.es + * + * This class represents a file signal source. Internally it uses a GNU Radio's + * gr_file_source as a connector to the data. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ +#define GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class ConfigurationInterface; + +/*! + * \brief Class that reads signals samples from files at different frequency bands + * and adapts it to a SignalSourceInterface + */ +class MultichannelFileSignalSource : public GNSSBlockInterface +{ +public: + MultichannelFileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); + + virtual ~MultichannelFileSignalSource(); + + 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_; + } + + 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_vec_.at(0); + } + + 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: + uint64_t samples_; + int64_t sampling_frequency_; + uint32_t n_channels_; + std::vector filename_vec_; + std::string item_type_; + bool repeat_; + std::string role_; + uint32_t in_streams_; + uint32_t out_streams_; + std::vector file_source_vec_; + boost::shared_ptr valve_; + gr::blocks::file_sink::sptr sink_; + std::vector throttle_vec_; + boost::shared_ptr queue_; + size_t item_size_; + // Throttle control + bool enable_throttle_control_; +}; + +#endif /* GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ */ diff --git a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc index 19626a5d4..d599684ff 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc +++ b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc @@ -44,8 +44,8 @@ Gnss_Sdr_Valve::Gnss_Sdr_Valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue, bool stop_flowgraph) : gr::sync_block("valve", - gr::io_signature::make(1, 1, sizeof_stream_item), - gr::io_signature::make(1, 1, sizeof_stream_item)), + gr::io_signature::make(1, 20, sizeof_stream_item), + gr::io_signature::make(1, 20, sizeof_stream_item)), d_nitems(nitems), d_ncopied_items(0), d_queue(std::move(queue)), @@ -99,11 +99,17 @@ int Gnss_Sdr_Valve::work(int noutput_items, { return 0; } - memcpy(output_items[0], input_items[0], n * input_signature()->sizeof_stream_item(0)); + //multichannel support + for (int ch = 0; ch < output_items.size(); ch++) + { + memcpy(output_items[ch], input_items[ch], n * input_signature()->sizeof_stream_item(ch)); + } d_ncopied_items += n; return n; } - - memcpy(output_items[0], input_items[0], noutput_items * input_signature()->sizeof_stream_item(0)); + for (int ch = 0; ch < output_items.size(); ch++) + { + memcpy(output_items[ch], input_items[ch], noutput_items * input_signature()->sizeof_stream_item(ch)); + } return noutput_items; } diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index b4ede27ac..7976d99da 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -97,6 +97,7 @@ #include "ishort_to_cshort.h" #include "labsat_signal_source.h" #include "mmse_resampler_conditioner.h" +#include "multichannel_file_signal_source.h" #include "notch_filter.h" #include "notch_filter_lite.h" #include "nsr_file_signal_source.h" @@ -1261,6 +1262,21 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } + catch (const std::exception& e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation == "Multichannel_File_Signal_Source") + { + try + { + std::unique_ptr block_(new MultichannelFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception& e) { std::cout << "GNSS-SDR program ended." << std::endl; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4282d26ee..8af07e1e7 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -215,7 +215,7 @@ void GNSSFlowgraph::connect() } DLOG(INFO) << "blocks connected internally"; - // Signal Source (i) > Signal conditioner (i) > +// Signal Source (i) > Signal conditioner (i) > #ifndef ENABLE_FPGA int RF_Channels = 0; int signal_conditioner_ID = 0; @@ -249,10 +249,13 @@ void GNSSFlowgraph::connect() DLOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); DLOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 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) { - 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); + 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); + } } else { @@ -819,7 +822,7 @@ void GNSSFlowgraph::disconnect() for (int j = 0; j < RF_Channels; j++) { - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 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) { top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); } diff --git a/src/utils/rinex2assist/CMakeLists.txt b/src/utils/rinex2assist/CMakeLists.txt index 312462ea1..78c07c428 100644 --- a/src/utils/rinex2assist/CMakeLists.txt +++ b/src/utils/rinex2assist/CMakeLists.txt @@ -99,3 +99,5 @@ else() message(STATUS "Boost Iostreams library not found.") message(STATUS " rinex2assist will not be built.") endif() + +set(Boost_FOUND TRUE) # trick for summary report