diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index bac9aee3d..3d786bb46 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -139,6 +139,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES file_signal_source.cc gen_signal_source.cc nsr_file_signal_source.cc spir_file_signal_source.cc + spir_gss6450_file_signal_source.cc rtl_tcp_signal_source.cc ${OPT_DRIVER_SOURCES} ) diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc new file mode 100644 index 000000000..f19d9d3d6 --- /dev/null +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc @@ -0,0 +1,284 @@ +/*! + * \file spir_gss6450_file_signal_source.cc + * \brief Implementation of a class that reads signals samples from a SPIR file + * and adapts it to a SignalSourceInterface. + * \author Antonio Ramos, 2017 antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is 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 "spir_gss6450_file_signal_source.h" +#include +#include +#include +#include +#include +#include +#include "configuration_interface.h" + +using google::LogMessage; + + +SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, + std::string role, unsigned int in_streams, unsigned int out_streams, gr::msg_queue::sptr queue) : + role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue) +{ + std::string default_filename = "../data/my_capture.dat"; + std::string default_dump_filename = "../data/my_capture_dump.dat"; + item_type_ = "int"; + + samples_ = configuration->property(role + ".samples", 0); + sampling_frequency_ = configuration->property(role + ".sampling_frequency", 0.0); + filename_ = configuration->property(role + ".filename", default_filename); + repeat_ = configuration->property(role + ".repeat", false); + dump_ = configuration->property(role + ".dump", false); + endian_swap_ = configuration->property(role + ".endian", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); + adc_bits_ = configuration->property(role + ".adc_bits", 4); + n_channels_ = configuration->property(role + ".total_channels", 1); + sel_ch_ = configuration->property(role + ".sel_ch", 1); + item_size_ = sizeof(int); + long bytes_seek = configuration->property(role + ".bytes_to_skip", 65536); + double sample_size_byte = static_cast(adc_bits_) / 4.0; + + if(sel_ch_ > n_channels_) { LOG(WARNING) << "Invalid RF channel selection"; } + if(n_channels_ > 1) + { + for(unsigned int i = 0; i < (n_channels_ - 1); i++) + { + null_sinks_.push_back(gr::blocks::null_sink::make(item_size_)); + } + DLOG(INFO)<< "NUMBER OF NULL SINKS = " << null_sinks_.size(); + } + try + { + file_source_ = gr::blocks::file_source::make(item_size_, filename_.c_str(), repeat_); + file_source_->seek(bytes_seek / item_size_, SEEK_SET); + unpack_spir_ = make_unpack_spir_gss6450_samples(adc_bits_); + deint_ = gr::blocks::deinterleave::make(item_size_); + } + catch (const std::exception &e) + { + 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(WARNING) << "file_signal_source: Unable to open the samples file " + << filename_.c_str() << ", exiting the program."; + throw(e); + } + DLOG(INFO) << "file_source(" << file_source_->unique_id() << ")"; + + if(samples_ == 0) // read all file + { + /*! + * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. + * A possible solution is to compute the file length in samples using file size, excluding the last 2 milliseconds, and enable always the + * valve block + */ + std::ifstream file (filename_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + LOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); + } + else + { + std::cout << "file_signal_source: Unable to open the samples file " << filename_.c_str() << std::endl; + LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_.c_str(); + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename_ << ", which contains " << size << " [bytes]" << std::endl; + std::cout.precision (ss); + + if(size > 0) + { + samples_ = static_cast(floor(static_cast(size - bytes_seek) / (sample_size_byte * static_cast(n_channels_)))); + samples_ = samples_- static_cast(ceil(0.002 * sampling_frequency_)); //process all the samples available in the file excluding the last 2 ms + } + } + + CHECK(samples_ > 0) << "File does not contain enough samples to process."; + double signal_duration_s = static_cast(samples_) / sampling_frequency_; + LOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; + std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; + + valve_ = gnss_sdr_make_valve(sizeof(gr_complex), samples_, queue_); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + + if (dump_) + { + sink_ = gr::blocks::file_sink::make(sizeof(gr_complex), dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << sink_->unique_id() << ")"; + } + if (enable_throttle_control_) + { + throttle_ = gr::blocks::throttle::make(sizeof(gr_complex), sampling_frequency_); + } + if (endian_swap_) + { + endian_ = gr::blocks::endian_swap::make(item_size_); + } + 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_; +} + + +SpirGSS6450FileSignalSource::~SpirGSS6450FileSignalSource() +{} + + +void SpirGSS6450FileSignalSource::connect(gr::top_block_sptr top_block) +{ + if (samples_ > 0) + { + top_block->connect(file_source_, 0, deint_, 0); + if(endian_swap_) + { + top_block->connect(deint_, sel_ch_ - 1, endian_ ,0); + top_block->connect(endian_, 0, unpack_spir_, 0); + } + else + { + top_block->connect(deint_, sel_ch_ - 1, unpack_spir_, 0); + } + if(n_channels_ > 1) + { + unsigned int aux = 0; + for(unsigned int i = 0; i < n_channels_; i++) + { + if(i != (sel_ch_ - 1)) + { + top_block->connect(deint_, i, null_sinks_.at(aux), 0); + aux++; + } + } + } + if (enable_throttle_control_) + { + top_block->connect(unpack_spir_, 0, throttle_, 0); + top_block->connect(throttle_, 0, valve_, 0); + } + else + { + top_block->connect(unpack_spir_, 0, valve_, 0); + } + if(dump_) + { + top_block->connect(valve_, 0, sink_, 0); + } + } + else + { + LOG(WARNING) << "0 samples to read"; + } +} + + +void SpirGSS6450FileSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (samples_ > 0) + { + top_block->disconnect(file_source_, 0, deint_, 0); + if(endian_swap_) + { + top_block->disconnect(deint_, sel_ch_ - 1, endian_ ,0); + top_block->disconnect(endian_, 0, unpack_spir_, 0); + } + else + { + top_block->disconnect(deint_, sel_ch_ - 1, unpack_spir_, 0); + } + if(n_channels_ > 1) + { + unsigned int aux = 0; + for(unsigned int i = 0; i < n_channels_; i++) + { + if(i != (sel_ch_ - 1)) + { + top_block->disconnect(deint_, i, null_sinks_.at(aux), 0); + aux++; + } + } + } + if (enable_throttle_control_) + { + top_block->disconnect(unpack_spir_, 0, throttle_, 0); + top_block->disconnect(throttle_, 0, valve_, 0); + } + else + { + top_block->disconnect(unpack_spir_, 0, valve_, 0); + } + if(dump_) + { + top_block->disconnect(valve_, 0, sink_, 0); + } + } + else + { + LOG(WARNING) << "Nothing to disconnect"; + } +} + + +gr::basic_block_sptr SpirGSS6450FileSignalSource::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 SpirGSS6450FileSignalSource::get_right_block() +{ + if(samples_ > 0) { return valve_; } + else + { + if(enable_throttle_control_) { return throttle_; } + else { return unpack_spir_; } + } +} diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h new file mode 100644 index 000000000..caa26c8fb --- /dev/null +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h @@ -0,0 +1,137 @@ +/*! + * \file spir_gss6450_file_signal_source.h + * \brief Implementation of a class that reads signals samples from a SPIR file + * and adapts it to a SignalSourceInterface. + * \author Antonio Ramos, 2017 antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is 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_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ +#define GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gnss_block_interface.h" +#include "gnss_sdr_valve.h" +#include "unpack_spir_gss6450_samples.h" + + +class ConfigurationInterface; + +/*! + * \brief Class that reads signals samples from a file + * and adapts it to a SignalSourceInterface + */ +class SpirGSS6450FileSignalSource: public GNSSBlockInterface +{ +public: + SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, std::string role, + unsigned int in_streams, unsigned int out_streams, gr::msg_queue::sptr queue); + + virtual ~SpirGSS6450FileSignalSource(); + inline std::string role() override + { + return role_; + } + + inline std::string implementation() override + { + return "Spir_GSS6450_File_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + 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 long sampling_frequency() const + { + return sampling_frequency_; + } + + inline long samples() const + { + return samples_; + } + +private: + unsigned long long samples_; + double sampling_frequency_; + std::string filename_; + bool repeat_; + bool dump_; //Enables dumping the gr_complex sample output + bool enable_throttle_control_; + bool endian_swap_; + std::string dump_filename_; + std::string role_; + std::string item_type_; + unsigned int in_streams_; + unsigned int out_streams_; + unsigned int adc_bits_; + unsigned int n_channels_; + unsigned int sel_ch_; + gr::blocks::file_source::sptr file_source_; + gr::blocks::deinterleave::sptr deint_; + gr::blocks::endian_swap::sptr endian_; + std::vector null_sinks_; + unpack_spir_gss6450_samples_sptr unpack_spir_; + boost::shared_ptr valve_; + gr::blocks::file_sink::sptr sink_; + gr::blocks::throttle::sptr throttle_; + gr::msg_queue::sptr queue_; + size_t item_size_; +}; + +#endif /*GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index 4159321f3..67b9f3162 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -23,6 +23,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES unpack_intspir_1bit_samples.cc rtl_tcp_signal_source_c.cc unpack_2bit_samples.cc + unpack_spir_gss6450_samples.cc ) include_directories( diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc new file mode 100644 index 000000000..6a7bf869a --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.cc @@ -0,0 +1,106 @@ +/*! + * \file unpack_spir_gss6450_samples.cc + * + * \brief Unpacks SPIR int samples + * \author Antonio Ramos, antonio(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is 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 "unpack_spir_gss6450_samples.h" +#include + + + +unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples(unsigned int adc_nbit) +{ + return unpack_spir_gss6450_samples_sptr(new unpack_spir_gss6450_samples(adc_nbit)); +} + + +unpack_spir_gss6450_samples::unpack_spir_gss6450_samples(unsigned int adc_nbit) : gr::sync_interpolator("unpack_spir_gss6450_samples", + gr::io_signature::make(1, 1, sizeof(int)), + gr::io_signature::make(1, 1, sizeof(gr_complex)), 16 / adc_nbit) +{ + adc_bits = adc_nbit; + i_data = 0; + q_data = 0; + samples_per_int = 16 / adc_bits; + if(adc_bits == 2) + { + mask_data = 0x00000003; + map_ = {0, 1, -2, -1}; + } + else + { + mask_data = 0x0000000F; + map_ = {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}; + } +} + + +unpack_spir_gss6450_samples::~unpack_spir_gss6450_samples() +{} + +void unpack_spir_gss6450_samples::process_sample(gr_complex& out) +{ + out = gr_complex(0.5, 0.5); + compute_two_complement(i_data); + compute_two_complement(q_data); + out += gr_complex(static_cast(i_data), static_cast(q_data)); +} + + +int unpack_spir_gss6450_samples::work(int noutput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + const int* in = reinterpret_cast(input_items[0]); + gr_complex* out = reinterpret_cast(output_items[0]); + unsigned int n_sample = 0; + unsigned int in_counter = 0; + for(int i = 0; i < noutput_items; i++) + { + int sample_aux = in[in_counter]; + int aux_i = sample_aux; + int aux_q = sample_aux; + int i_shift = adc_bits * 2 * (samples_per_int - n_sample - 1) + adc_bits; + int q_shift = adc_bits * 2 * (samples_per_int - n_sample - 1); + i_data = (aux_i >> i_shift) & mask_data; + q_data = (aux_q >> q_shift) & mask_data; + process_sample(out[samples_per_int * in_counter + samples_per_int - n_sample - 1]); + n_sample++; + if(n_sample == samples_per_int) + { + n_sample = 0; + in_counter++; + } + } + return noutput_items; +} + +void unpack_spir_gss6450_samples::compute_two_complement(int& data) +{ + data = map_[data]; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h new file mode 100644 index 000000000..25db1a9d6 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_spir_gss6450_samples.h @@ -0,0 +1,64 @@ +/*! + * \file unpack_spir_gss6450_samples.h + * + * \brief Unpacks SPIR int samples + * \author Antonio Ramos, antonio.ramos(at)cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is not part of GNSS-SDR. + * + * GNSS-SDR is 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_UNPACK_SPIR_GSS6450_SAMPLES_H +#define GNSS_SDR_UNPACK_SPIR_GSS6450_SAMPLES_H + +#include +#include + +class unpack_spir_gss6450_samples; + +typedef boost::shared_ptr unpack_spir_gss6450_samples_sptr; + +unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples(unsigned int adc_nbit); + + +class unpack_spir_gss6450_samples: public gr::sync_interpolator +{ +public: + int work(int noutput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + friend unpack_spir_gss6450_samples_sptr make_unpack_spir_gss6450_samples_sptr(unsigned int adc_nbit); + unpack_spir_gss6450_samples(unsigned int adc_nbit); + ~unpack_spir_gss6450_samples(); + +private: + unsigned int adc_bits; + unsigned int samples_per_int; + void process_sample(gr_complex& out); + void compute_two_complement(int& data); + int i_data; + int q_data; + int mask_data; + std::vector map_; +}; + +#endif diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index bdf34dc22..322577e62 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -48,6 +48,7 @@ #include "nsr_file_signal_source.h" #include "two_bit_cpx_file_signal_source.h" #include "spir_file_signal_source.h" +#include "spir_gss6450_file_signal_source.h" #include "rtl_tcp_signal_source.h" #include "two_bit_packed_file_signal_source.h" #include "channel.h" @@ -864,6 +865,21 @@ std::unique_ptr GNSSBlockFactory::GetBlock( out_streams, queue)); block = std::move(block_); + } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation.compare("Spir_GSS6450_File_Signal_Source") == 0) + { + try + { + std::unique_ptr block_(new SpirGSS6450FileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } catch (const std::exception &e) {