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..52081e2ad
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc
@@ -0,0 +1,314 @@
+/*!
+ * \file file_signal_source.cc
+ * \brief Implementation of a class that reads signals samples from a file
+ * and adapts it to a SignalSourceInterface
+ * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com
+ * Javier Arribas, 2011 jarribas(at)cttc.es
+ *
+ * -------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 (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..a800fb909
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h
@@ -0,0 +1,131 @@
+/*!
+ * \file file_signal_source.h
+ * \brief Interface of a class that reads signals samples from a file
+ * and adapts it to a SignalSourceInterface
+ * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com
+ *
+ * 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-2018 (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 a file
+ * 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 "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);
}