From c97e12dbe0e368c4910cbb431c173fa398a9262b Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Fri, 20 May 2022 10:40:30 +0200 Subject: [PATCH 01/31] Adding 4 bits complex samples signal source --- .../signal_source/adapters/CMakeLists.txt | 2 + .../four_bit_cpx_file_signal_source.cc | 102 ++++++++++++++++++ .../four_bit_cpx_file_signal_source.h | 71 ++++++++++++ .../unpack_byte_4bit_samples.cc | 16 +-- .../unpack_byte_4bit_samples.h | 4 +- src/core/receiver/gnss_block_factory.cc | 7 ++ 6 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc create mode 100644 src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 7a4c6e065..32a9c6bc9 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -99,6 +99,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES labsat_signal_source.cc two_bit_cpx_file_signal_source.cc two_bit_packed_file_signal_source.cc + four_bit_cpx_file_signal_source.cc file_timestamp_signal_source.cc ${OPT_DRIVER_SOURCES} ) @@ -117,6 +118,7 @@ set(SIGNAL_SOURCE_ADAPTER_HEADERS labsat_signal_source.h two_bit_cpx_file_signal_source.h two_bit_packed_file_signal_source.h + four_bit_cpx_file_signal_source.h file_timestamp_signal_source.h ${OPT_DRIVER_HEADERS} ) diff --git a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc new file mode 100644 index 000000000..0fc521fe9 --- /dev/null +++ b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc @@ -0,0 +1,102 @@ +/*! + * \file four_bit_cpx_file_signal_source.cc + * \brief Implementation of a class that reads signals samples from a 2 bit complex sampler front-end file + * and adapts it to a SignalSourceInterface. + * \author Javier Arribas, 2015 jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "four_bit_cpx_file_signal_source.h" +#include "configuration_interface.h" +#include "gnss_sdr_string_literals.h" +#include + +using namespace std::string_literals; + + +FourBitCpxFileSignalSource::FourBitCpxFileSignalSource( + const ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, unsigned int out_streams, + Concurrent_Queue* queue) + : FileSourceBase(configuration, role, "Four_Bit_Cpx_File_Signal_Source"s, queue, "byte"s) +{ + sample_type_ = configuration->property(role + ".sample_type", "iq"s); + // the complex-ness of the input is inferred from the output type + if (sample_type_ == "iq") + { + reverse_interleaving_ = false; + } + else if (sample_type_ == "qi") + { + reverse_interleaving_ = true; + } + else + { + LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: "; + } + + + 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"; + } +} + + +std::tuple FourBitCpxFileSignalSource::itemTypeToSize() +{ + auto is_complex = false; + auto item_size = size_t(sizeof(char)); // default + + if (item_type() == "byte") + { + item_size = sizeof(char); + } + else + { + LOG(WARNING) << item_type() << " unrecognized item type. Using byte."; + } + + return std::make_tuple(item_size, is_complex); +} + +// 1 byte -> 1 complex samples +double FourBitCpxFileSignalSource::packetsPerSample() const { return 1.0; } +gnss_shared_ptr FourBitCpxFileSignalSource::source() const { return inter_shorts_to_cpx_; } + + +void FourBitCpxFileSignalSource::create_file_source_hook() +{ + unpack_byte_ = make_unpack_byte_4bit_samples(); + DLOG(INFO) << "unpack_byte_2bit_cpx_samples(" << unpack_byte_->unique_id() << ")"; + inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, reverse_interleaving_); // I/Q swap enabled + DLOG(INFO) << "interleaved_short_to_complex(" << inter_shorts_to_cpx_->unique_id() << ")"; +} + +void FourBitCpxFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) +{ + top_block->connect(file_source(), 0, unpack_byte_, 0); + top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); + DLOG(INFO) << "connected file_source to unpacker"; +} + +void FourBitCpxFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) +{ + top_block->disconnect(file_source(), 0, unpack_byte_, 0); + top_block->disconnect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); + DLOG(INFO) << "disconnected file_source from unpacker"; +} diff --git a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h new file mode 100644 index 000000000..ac9b5c3fb --- /dev/null +++ b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h @@ -0,0 +1,71 @@ +/*! + * \file FOUR_BIT_cpx_file_signal_source.h + * \brief Interface of a class that reads signals samples from a 2 bit complex sampler front-end file + * and adapts it to a SignalSourceInterface. + * \author Javier Arribas, 2015 jarribas(at)cttc.es + * + * This class represents a file signal source. + * + * ----------------------------------------------------------------------------- + * + * 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_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H +#define GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H + +#include "file_source_base.h" +#include "unpack_byte_4bit_samples.h" +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +/*! + * \brief Class that reads signals samples from a file + * and adapts it to a SignalSourceInterface + */ +class FourBitCpxFileSignalSource : public FileSourceBase +{ +public: + FourBitCpxFileSignalSource(const ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, + Concurrent_Queue* queue); + + ~FourBitCpxFileSignalSource() = default; + +protected: + std::tuple itemTypeToSize() override; + double packetsPerSample() const override; + gnss_shared_ptr source() const override; + void create_file_source_hook() override; + void pre_connect_hook(gr::top_block_sptr top_block) override; + void pre_disconnect_hook(gr::top_block_sptr top_block) override; + +private: + unpack_byte_4bit_samples_sptr unpack_byte_; + gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_; + std::string sample_type_; + bool reverse_interleaving_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc index ca82f23b5..ccc04374f 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc @@ -26,8 +26,8 @@ unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples() unpack_byte_4bit_samples::unpack_byte_4bit_samples() : sync_interpolator("unpack_byte_4bit_samples", - gr::io_signature::make(1, 1, sizeof(signed char)), - gr::io_signature::make(1, 1, sizeof(signed char)), + gr::io_signature::make(1, 1, sizeof(int8_t)), + gr::io_signature::make(1, 1, sizeof(int16_t)), 2) { } @@ -37,8 +37,8 @@ int unpack_byte_4bit_samples::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - const auto *in = reinterpret_cast(input_items[0]); - auto *out = reinterpret_cast(output_items[0]); + const auto *in = reinterpret_cast(input_items[0]); + auto *out = reinterpret_cast(output_items[0]); int n = 0; unsigned char tmp_char2; for (int i = 0; i < noutput_items / 2; i++) @@ -46,21 +46,21 @@ int unpack_byte_4bit_samples::work(int noutput_items, tmp_char2 = in[i] & 0x0F; if (tmp_char2 >= 8) { - out[n++] = 2 * (tmp_char2 - 16) + 1; + out[n++] = static_cast(2 * (tmp_char2 - 16) + 1); } else { - out[n++] = 2 * tmp_char2 + 1; + out[n++] = static_cast(2 * tmp_char2 + 1); } tmp_char2 = in[i] >> 4; tmp_char2 = tmp_char2 & 0x0F; if (tmp_char2 >= 8) { - out[n++] = 2 * (tmp_char2 - 16) + 1; + out[n++] = static_cast(2 * (tmp_char2 - 16) + 1); } else { - out[n++] = 2 * tmp_char2 + 1; + out[n++] = static_cast(2 * tmp_char2 + 1); } } return noutput_items; diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h index 1d3d91da6..2b75c763c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h @@ -20,8 +20,8 @@ #ifndef GNSS_SDR_UNPACK_BYTE_4BIT_SAMPLES_H #define GNSS_SDR_UNPACK_BYTE_4BIT_SAMPLES_H +#include "gnss_block_interface.h" #include -#include /** \addtogroup Signal_Source * \{ */ @@ -31,7 +31,7 @@ class unpack_byte_4bit_samples; -using unpack_byte_4bit_samples_sptr = std::shared_ptr; +using unpack_byte_4bit_samples_sptr = gnss_shared_ptr; unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples(); diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 6a92df891..adba9c0df 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -41,6 +41,7 @@ #include "file_signal_source.h" #include "file_timestamp_signal_source.h" #include "fir_filter.h" +#include "four_bit_cpx_file_signal_source.h" #include "freq_xlating_fir_filter.h" #include "galileo_e1_dll_pll_veml_tracking.h" #include "galileo_e1_pcps_8ms_ambiguous_acquisition.h" @@ -694,6 +695,12 @@ std::unique_ptr GNSSBlockFactory::GetBlock( out_streams, queue); block = std::move(block_); } + else if (implementation == "Four_Bit_Cpx_File_Signal_Source") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } else if (implementation == "Two_Bit_Packed_File_Signal_Source") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, From 742113c55f008128bf44e86c588e4251845d66c7 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Mon, 23 May 2022 12:30:12 +0200 Subject: [PATCH 02/31] Adding timestamp capability to four bits signal source --- .../adapters/file_timestamp_signal_source.cc | 21 ++++++++++--- .../four_bit_cpx_file_signal_source.cc | 31 +++++++++++++++++-- .../four_bit_cpx_file_signal_source.h | 5 +++ .../signal_source/libs/gnss_sdr_timestamp.cc | 10 +++--- .../signal_source/libs/gnss_sdr_timestamp.h | 10 ++++-- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc index 1cc29e40a..32d27ac19 100644 --- a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc @@ -16,7 +16,6 @@ #include "file_timestamp_signal_source.h" #include "gnss_sdr_flags.h" #include "gnss_sdr_string_literals.h" -#include "gnss_sdr_timestamp.h" #include #include @@ -51,10 +50,22 @@ gnss_shared_ptr FileTimestampSignalSource::source() const { return ti void FileTimestampSignalSource::create_file_source_hook() { - timestamp_block_ = gnss_sdr_make_Timestamp( - std::get<0>(itemTypeToSize()), - timestamp_file_, - timestamp_clock_offset_ms_); + if (is_complex() == false) + { + timestamp_block_ = gnss_sdr_make_Timestamp( + std::get<0>(itemTypeToSize()), + timestamp_file_, + timestamp_clock_offset_ms_, + source_item_size() * 2); + } + else + { + timestamp_block_ = gnss_sdr_make_Timestamp( + std::get<0>(itemTypeToSize()), + timestamp_file_, + timestamp_clock_offset_ms_, + source_item_size()); + } DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")"; } diff --git a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc index 0fc521fe9..c22ababb3 100644 --- a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc @@ -17,6 +17,7 @@ #include "four_bit_cpx_file_signal_source.h" #include "configuration_interface.h" +#include "gnss_sdr_flags.h" #include "gnss_sdr_string_literals.h" #include @@ -28,7 +29,9 @@ FourBitCpxFileSignalSource::FourBitCpxFileSignalSource( const std::string& role, unsigned int in_streams, unsigned int out_streams, Concurrent_Queue* queue) - : FileSourceBase(configuration, role, "Four_Bit_Cpx_File_Signal_Source"s, queue, "byte"s) + : FileSourceBase(configuration, role, "Four_Bit_Cpx_File_Signal_Source"s, queue, "byte"s), + timestamp_file_(configuration->property(role + ".timestamp_filename"s, ""s)), + timestamp_clock_offset_ms_(configuration->property(role + ".timestamp_clock_offset_ms"s, 0.0)) { sample_type_ = configuration->property(role + ".sample_type", "iq"s); // the complex-ness of the input is inferred from the output type @@ -54,6 +57,12 @@ FourBitCpxFileSignalSource::FourBitCpxFileSignalSource( { LOG(ERROR) << "This implementation only supports one output stream"; } + + // override value with commandline flag, if present + if (FLAGS_timestamp_source != "-") + { + timestamp_file_ = FLAGS_timestamp_source; + } } @@ -76,7 +85,7 @@ std::tuple FourBitCpxFileSignalSource::itemTypeToSize() // 1 byte -> 1 complex samples double FourBitCpxFileSignalSource::packetsPerSample() const { return 1.0; } -gnss_shared_ptr FourBitCpxFileSignalSource::source() const { return inter_shorts_to_cpx_; } +gnss_shared_ptr FourBitCpxFileSignalSource::source() const { return timestamp_block_; } void FourBitCpxFileSignalSource::create_file_source_hook() @@ -85,6 +94,14 @@ void FourBitCpxFileSignalSource::create_file_source_hook() DLOG(INFO) << "unpack_byte_2bit_cpx_samples(" << unpack_byte_->unique_id() << ")"; inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, reverse_interleaving_); // I/Q swap enabled DLOG(INFO) << "interleaved_short_to_complex(" << inter_shorts_to_cpx_->unique_id() << ")"; + if (timestamp_file_.size() > 1) + { + timestamp_block_ = gnss_sdr_make_Timestamp(sizeof(gr_complex), + timestamp_file_, + timestamp_clock_offset_ms_, + 1); + DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")"; + } } void FourBitCpxFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) @@ -92,10 +109,20 @@ void FourBitCpxFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block) top_block->connect(file_source(), 0, unpack_byte_, 0); top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); DLOG(INFO) << "connected file_source to unpacker"; + if (timestamp_file_.size() > 1) + { + top_block->connect(inter_shorts_to_cpx_, 0, timestamp_block_, 0); + DLOG(INFO) << "connected file_source to timestamp_block_"; + } } void FourBitCpxFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) { + if (timestamp_file_.size() > 1) + { + top_block->disconnect(inter_shorts_to_cpx_, 0, timestamp_block_, 0); + DLOG(INFO) << "disconnected file_source from timestamp_block_"; + } top_block->disconnect(file_source(), 0, unpack_byte_, 0); top_block->disconnect(unpack_byte_, 0, inter_shorts_to_cpx_, 0); DLOG(INFO) << "disconnected file_source from unpacker"; diff --git a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h index ac9b5c3fb..a36776afb 100644 --- a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.h @@ -21,6 +21,7 @@ #define GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H #include "file_source_base.h" +#include "gnss_sdr_timestamp.h" #include "unpack_byte_4bit_samples.h" #include #include @@ -63,6 +64,10 @@ private: gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_; std::string sample_type_; bool reverse_interleaving_; + + gnss_shared_ptr timestamp_block_; + std::string timestamp_file_; + double timestamp_clock_offset_ms_; }; diff --git a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.cc b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.cc index 9ac458c04..857acf1e7 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.cc +++ b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.cc @@ -28,22 +28,23 @@ Gnss_Sdr_Timestamp::Gnss_Sdr_Timestamp(size_t sizeof_stream_item, - std::string timestamp_file, double clock_offset_ms) + std::string timestamp_file, double clock_offset_ms, int items_to_samples) : gr::sync_block("Timestamp", gr::io_signature::make(1, 20, sizeof_stream_item), gr::io_signature::make(1, 20, sizeof_stream_item)), d_timefile(std::move(timestamp_file)), d_clock_offset_ms(clock_offset_ms), d_fraction_ms_offset(modf(d_clock_offset_ms, &d_integer_ms_offset)), // optional clockoffset parameter to convert UTC timestamps to GPS time in some receiver's configuration + d_items_to_samples(items_to_samples), d_next_timetag_samplecount(0), d_get_next_timetag(true) { } -gnss_shared_ptr gnss_sdr_make_Timestamp(size_t sizeof_stream_item, std::string timestamp_file, double clock_offset_ms) +gnss_shared_ptr gnss_sdr_make_Timestamp(size_t sizeof_stream_item, std::string timestamp_file, double clock_offset_ms, int items_to_samples) { - gnss_shared_ptr Timestamp_(new Gnss_Sdr_Timestamp(sizeof_stream_item, std::move(timestamp_file), clock_offset_ms)); + gnss_shared_ptr Timestamp_(new Gnss_Sdr_Timestamp(sizeof_stream_item, std::move(timestamp_file), clock_offset_ms, items_to_samples)); return Timestamp_; } @@ -110,8 +111,7 @@ int Gnss_Sdr_Timestamp::work(int noutput_items, for (size_t ch = 0; ch < output_items.size(); ch++) { std::memcpy(output_items[ch], input_items[ch], noutput_items * input_signature()->sizeof_stream_item(ch)); - uint64_t bytes_to_samples = 2; // todo: improve this.. hardcoded 2 bytes -> 1 complex sample! - int64_t diff_samplecount = uint64diff(this->nitems_written(ch), d_next_timetag_samplecount * bytes_to_samples); + int64_t diff_samplecount = uint64diff(this->nitems_written(ch), d_next_timetag_samplecount * d_items_to_samples); // std::cout << "diff_samplecount: " << diff_samplecount << ", noutput_items: " << noutput_items << "\n"; if (diff_samplecount <= noutput_items and std::labs(diff_samplecount) <= noutput_items) { diff --git a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h index 6a7f762e2..11716ca82 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h +++ b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h @@ -39,7 +39,8 @@ class Gnss_Sdr_Timestamp; gnss_shared_ptr gnss_sdr_make_Timestamp( size_t sizeof_stream_item, std::string timestamp_file, - double clock_offset_ms); + double clock_offset_ms, + int items_to_samples); class Gnss_Sdr_Timestamp : public gr::sync_block @@ -54,11 +55,13 @@ private: friend gnss_shared_ptr gnss_sdr_make_Timestamp( size_t sizeof_stream_item, std::string timestamp_file, - double clock_offset_ms); + double clock_offset_ms, + int items_to_samples); Gnss_Sdr_Timestamp(size_t sizeof_stream_item, std::string timestamp_file, - double clock_offset_ms); + double clock_offset_ms, + int items_to_samples); int64_t uint64diff(uint64_t first, uint64_t second); bool read_next_timetag(); @@ -69,6 +72,7 @@ private: double d_fraction_ms_offset; double d_integer_ms_offset; uint64_t d_next_timetag_samplecount; + int d_items_to_samples; bool d_get_next_timetag; }; From 67e4d7c6e2b7c0cf21085fb42a800c1526f88132 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Mon, 23 May 2022 15:34:06 +0200 Subject: [PATCH 03/31] Added Galileo E6 experimental Pseudorange generation using signal source timetag propagation --- .../galileo_telemetry_decoder_gs.cc | 26 ++++++++++++++++++- .../galileo_telemetry_decoder_gs.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index db723cdf9..f672a6b21 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -85,7 +85,8 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( d_enable_navdata_monitor(conf.enable_navdata_monitor), d_dump_crc_stats(conf.dump_crc_stats), d_enable_reed_solomon_inav(false), - d_valid_timetag(false) + d_valid_timetag(false), + d_E6_TOW_set(false) { // prevent telemetry symbols accumulation in output buffers this->set_max_noutput_items(1); @@ -591,6 +592,7 @@ void galileo_telemetry_decoder_gs::set_satellite(const Gnss_Satellite &satellite d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); d_last_valid_preamble = d_sample_counter; d_sent_tlm_failed_msg = false; + d_E6_TOW_set = false; DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; DLOG(INFO) << "Navigation Satellite set to " << d_satellite; } @@ -607,6 +609,7 @@ void galileo_telemetry_decoder_gs::reset() d_inav_nav.set_TOW0_flag(false); d_last_valid_preamble = d_sample_counter; d_sent_tlm_failed_msg = false; + d_E6_TOW_set = false; d_stat = 0; d_viterbi->reset(); if (d_enable_reed_solomon_inav == true) @@ -1019,6 +1022,23 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__(( case 3: // CNAV { // TODO + // Obtain Galileo E6 TOW from timetags, if available + if (d_valid_timetag == true) + { + int rx_tow_at_preamble = d_current_timetag.tow_ms; + uint32_t predicted_tow_at_preamble_ms = 1000 * (rx_tow_at_preamble / 1000); // floor to integer number of seconds + + d_TOW_at_Preamble_ms = predicted_tow_at_preamble_ms; + //todo: compute tow at current symbol from the decoder delay similar as d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_FNAV_CODES_PER_SYMBOL * GALILEO_E5A_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = predicted_tow_at_preamble_ms + static_cast((GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS) * d_PRN_code_period_ms); + if (d_E6_TOW_set == false) + { + std::cout << " Sat PRN " << d_satellite.get_PRN() << " E6 TimeTag TOW at preamble: " << predicted_tow_at_preamble_ms + // << " [ms] TOW fraction: " << d_current_timetag.tow_ms_fraction + << " [ms] d_TOW_at_current_symbol_ms: " << d_TOW_at_current_symbol_ms << " [ms]\n"; + d_E6_TOW_set = true; + } + } } } } @@ -1078,6 +1098,10 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__(( case 3: // CNAV { // TODO + if (d_E6_TOW_set == true) + { + current_symbol.Flag_valid_word = true; + } break; } } diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index 59e5fcb01..98c1494a1 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -147,6 +147,7 @@ private: bool d_dump_crc_stats; bool d_enable_reed_solomon_inav; bool d_valid_timetag; + bool d_E6_TOW_set; }; From a45998d0db0f762bee177844dead7d39fc4c1e6f Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Mon, 23 May 2022 17:32:09 +0200 Subject: [PATCH 04/31] Fix computation of Galileo E6 pseudoranges using TOW from source timetag --- .../galileo_telemetry_decoder_gs.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index f672a6b21..2ff4a6612 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -1022,19 +1022,19 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__(( case 3: // CNAV { // TODO - // Obtain Galileo E6 TOW from timetags, if available + // Add option to use system time to estimate the preamble TOW + // Add option to use Galileo E1 or E5 TOW information.. + + // Done: Obtain Galileo E6 TOW from timetags, if available if (d_valid_timetag == true) { int rx_tow_at_preamble = d_current_timetag.tow_ms; uint32_t predicted_tow_at_preamble_ms = 1000 * (rx_tow_at_preamble / 1000); // floor to integer number of seconds - d_TOW_at_Preamble_ms = predicted_tow_at_preamble_ms; - //todo: compute tow at current symbol from the decoder delay similar as d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_FNAV_CODES_PER_SYMBOL * GALILEO_E5A_CODE_PERIOD_MS); - d_TOW_at_current_symbol_ms = predicted_tow_at_preamble_ms + static_cast((GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS) * d_PRN_code_period_ms); + d_TOW_at_current_symbol_ms = predicted_tow_at_preamble_ms + static_cast((d_required_symbols + 1) * d_PRN_code_period_ms); if (d_E6_TOW_set == false) { std::cout << " Sat PRN " << d_satellite.get_PRN() << " E6 TimeTag TOW at preamble: " << predicted_tow_at_preamble_ms - // << " [ms] TOW fraction: " << d_current_timetag.tow_ms_fraction << " [ms] d_TOW_at_current_symbol_ms: " << d_TOW_at_current_symbol_ms << " [ms]\n"; d_E6_TOW_set = true; } @@ -1064,8 +1064,10 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__(( } case 3: // CNAV { - // TODO - d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; // this is not the TOW! + if (d_E6_TOW_set == true) + { + d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; + } break; } } From 0eebe9c2deafdd6891f7e413a8e7e1a5a7917e23 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 24 May 2022 15:44:11 +0200 Subject: [PATCH 05/31] Fix four bits source adapter --- .../adapters/four_bit_cpx_file_signal_source.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc index c22ababb3..3ac128a05 100644 --- a/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/four_bit_cpx_file_signal_source.cc @@ -85,7 +85,17 @@ std::tuple FourBitCpxFileSignalSource::itemTypeToSize() // 1 byte -> 1 complex samples double FourBitCpxFileSignalSource::packetsPerSample() const { return 1.0; } -gnss_shared_ptr FourBitCpxFileSignalSource::source() const { return timestamp_block_; } +gnss_shared_ptr FourBitCpxFileSignalSource::source() const +{ + if (timestamp_file_.size() > 1) + { + return timestamp_block_; + } + else + { + return inter_shorts_to_cpx_; + } +} void FourBitCpxFileSignalSource::create_file_source_hook() From ea573359e0fbd46265eb78d8164623aca6d7851c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 24 May 2022 21:18:59 +0200 Subject: [PATCH 06/31] Print IGM messages if TOW is available --- src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 8 ++++++-- src/algorithms/PVT/libs/rtcm.cc | 8 ++++---- .../gnuradio_blocks/galileo_telemetry_decoder_gs.cc | 4 ++++ src/core/libs/galileo_e6_has_msg_receiver.cc | 8 ++++++++ src/core/system_parameters/galileo_cnav_message.cc | 2 ++ src/core/system_parameters/galileo_cnav_message.h | 5 +++++ src/core/system_parameters/galileo_has_data.h | 2 ++ src/core/system_parameters/galileo_has_page.h | 1 + 8 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 6fb9a2510..83299a356 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -1573,11 +1573,15 @@ void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg) const const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); if (msg_type_hash_code == d_galileo_has_data_sptr_type_hash_code) { - if (d_enable_has_messages) + const auto has_data = wht::any_cast>(pmt::any_ref(msg)); + if (d_has_simple_printer) { - const auto has_data = wht::any_cast>(pmt::any_ref(msg)); d_has_simple_printer->print_message(has_data.get()); } + if (d_rtcm_printer && has_data->tow <= 604800) + { + d_rtcm_printer->Print_IGM_Messages(*has_data.get()); + } } } catch (const wht::bad_any_cast& e) diff --git a/src/algorithms/PVT/libs/rtcm.cc b/src/algorithms/PVT/libs/rtcm.cc index 5beb3d9ea..bbd0abeb1 100644 --- a/src/algorithms/PVT/libs/rtcm.cc +++ b/src/algorithms/PVT/libs/rtcm.cc @@ -3428,7 +3428,7 @@ std::string Rtcm::get_IGM01_header(const Galileo_HAS_data& has_data, uint8_t nsy { std::string header; - uint32_t tow = 0; // TODO + uint32_t tow = has_data.tow; uint16_t ssr_provider_id = 0; // ? uint8_t igm_version = 0; // ? uint8_t ssr_solution_id = 0; // ? @@ -3505,7 +3505,7 @@ std::string Rtcm::get_IGM02_header(const Galileo_HAS_data& has_data, uint8_t nsy { std::string header; - uint32_t tow = 0; // TODO + uint32_t tow = has_data.tow; uint16_t ssr_provider_id = 0; // ? uint8_t igm_version = 0; // ? uint8_t ssr_solution_id = 0; // ? @@ -3576,7 +3576,7 @@ std::string Rtcm::get_IGM03_header(const Galileo_HAS_data& has_data, uint8_t nsy { std::string header; - uint32_t tow = 0; // TODO + uint32_t tow = has_data.tow; uint16_t ssr_provider_id = 0; // ? uint8_t igm_version = 0; // ? uint8_t ssr_solution_id = 0; // ? @@ -3661,7 +3661,7 @@ std::string Rtcm::get_IGM05_header(const Galileo_HAS_data& has_data, uint8_t nsy { std::string header; - uint32_t tow = 0; // TODO + uint32_t tow = has_data.tow; uint16_t ssr_provider_id = 0; // ? uint8_t igm_version = 0; // ? uint8_t ssr_solution_id = 0; // ? diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 2ff4a6612..53d4ced5b 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -571,6 +571,10 @@ void galileo_telemetry_decoder_gs::decode_CNAV_word(uint64_t time_stamp, float * } else { + if (d_E6_TOW_set == true) + { + d_cnav_nav.set_tow(d_TOW_at_Preamble_ms / 1000); + } const std::shared_ptr tmp_obj = std::make_shared(d_cnav_nav.get_HAS_encoded_page()); this->message_port_pub(pmt::mp("E6_HAS_from_TLM"), pmt::make_any(tmp_obj)); if (d_print_cnav_page == true) diff --git a/src/core/libs/galileo_e6_has_msg_receiver.cc b/src/core/libs/galileo_e6_has_msg_receiver.cc index 53fc3d6bc..6b4c326d2 100644 --- a/src/core/libs/galileo_e6_has_msg_receiver.cc +++ b/src/core/libs/galileo_e6_has_msg_receiver.cc @@ -26,6 +26,7 @@ #include // for DLOG #include // for gr::io_signature::make #include // for std::find, std::count +#include // for std::remainder #include // for size_t #include // for std::back_inserter #include // for std::numeric_limits @@ -111,6 +112,7 @@ void galileo_e6_has_msg_receiver::set_enable_navdata_monitor(bool enable) std::shared_ptr galileo_e6_has_msg_receiver::process_test_page(const pmt::pmt_t& msg) { int64_t timestamp = std::numeric_limits::max(); + uint32_t tow = std::numeric_limits::max(); try { const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); @@ -126,6 +128,7 @@ std::shared_ptr galileo_e6_has_msg_receiver::process_test_page d_current_has_status = HAS_data_page->has_status; d_current_message_id = HAS_data_page->message_id; timestamp = HAS_data_page->time_stamp; + tow = HAS_data_page->tow; if (d_printed_mids[d_current_message_id] == false) { process_HAS_page(*HAS_data_page.get()); @@ -146,6 +149,7 @@ std::shared_ptr galileo_e6_has_msg_receiver::process_test_page { d_HAS_data.has_status = d_current_has_status; d_HAS_data.message_id = d_current_message_id; + d_HAS_data.tow = tow - static_cast(std::remainder(tow, 3600)) + d_HAS_data.header.toh; auto has_data_ptr = std::make_shared(d_HAS_data); d_new_message = false; d_printed_mids[d_current_message_id] = true; @@ -160,6 +164,7 @@ void galileo_e6_has_msg_receiver::msg_handler_galileo_e6_has(const pmt::pmt_t& m { gr::thread::scoped_lock lock(d_setlock); // require mutex with msg_handler_galileo_e6_has function called by the scheduler int64_t timestamp = std::numeric_limits::max(); + uint32_t tow = std::numeric_limits::max(); try { const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); @@ -175,6 +180,7 @@ void galileo_e6_has_msg_receiver::msg_handler_galileo_e6_has(const pmt::pmt_t& m d_current_has_status = HAS_data_page->has_status; d_current_message_id = HAS_data_page->message_id; timestamp = HAS_data_page->time_stamp; + tow = HAS_data_page->tow; if (d_printed_mids[d_current_message_id] == false) { process_HAS_page(*HAS_data_page.get()); @@ -195,6 +201,7 @@ void galileo_e6_has_msg_receiver::msg_handler_galileo_e6_has(const pmt::pmt_t& m { d_HAS_data.has_status = d_current_has_status; d_HAS_data.message_id = d_current_message_id; + d_HAS_data.tow = tow - static_cast(std::remainder(tow, 3600)) + d_HAS_data.header.toh; d_printed_mids[d_current_message_id] = true; d_printed_timestamps[d_current_message_id] = timestamp; auto has_data_ptr = std::make_shared(d_HAS_data); @@ -399,6 +406,7 @@ int galileo_e6_has_msg_receiver::decode_message_type1(uint8_t message_id, uint8_ // Trigger HAS message content reading and fill the d_HAS_data object d_HAS_data = Galileo_HAS_data(); + d_HAS_data.tow = std::numeric_limits::max(); // Unknown read_MT1_header(decoded_message_type_1.substr(0, GALILEO_CNAV_MT1_HEADER_BITS)); diff --git a/src/core/system_parameters/galileo_cnav_message.cc b/src/core/system_parameters/galileo_cnav_message.cc index 0b93f6bf0..e514b00b7 100644 --- a/src/core/system_parameters/galileo_cnav_message.cc +++ b/src/core/system_parameters/galileo_cnav_message.cc @@ -21,6 +21,7 @@ #include // for boost::dynamic_bitset #include #include // for reverse +#include #include using CRC_Galileo_CNAV_type = boost::crc_optimal<24, 0x1864CFBU, 0x0, 0x0, false, false>; @@ -60,6 +61,7 @@ void Galileo_Cnav_Message::read_HAS_page(const std::string& page_string) const std::bitset checksum(CRC_data); d_new_HAS_page = false; has_page = Galileo_HAS_page(); + has_page.tow = std::numeric_limits::max(); // Unknown d_flag_CRC_test = CRC_test(Word_for_CRC_bits, checksum.to_ulong()); if (d_flag_CRC_test == true) { diff --git a/src/core/system_parameters/galileo_cnav_message.h b/src/core/system_parameters/galileo_cnav_message.h index 90444175b..436aed93f 100644 --- a/src/core/system_parameters/galileo_cnav_message.h +++ b/src/core/system_parameters/galileo_cnav_message.h @@ -74,6 +74,11 @@ public: has_page.time_stamp = time_stamp; } + inline void set_tow(uint32_t tow) + { + has_page.tow = tow; + } + private: uint8_t read_has_page_header_parameter(const std::bitset& bits, const std::pair& parameter) const; bool CRC_test(const std::bitset& bits, uint32_t checksum) const; diff --git a/src/core/system_parameters/galileo_has_data.h b/src/core/system_parameters/galileo_has_data.h index a4a3c289e..79b50eaeb 100644 --- a/src/core/system_parameters/galileo_has_data.h +++ b/src/core/system_parameters/galileo_has_data.h @@ -104,6 +104,8 @@ public: std::vector> phase_bias; //!< PB - Phase bias for the m-th signal of the n-th SV. See HAS SIS ICD 1.0 Section 5.2.6 std::vector> phase_discontinuity_indicator; //!< PDI - Phase Discontinuity Indicator. See HAS SIS ICD 1.0 Section 5.2.6. + uint32_t tow; //!< Time of Week + mt1_header header; //!< MT1 Header parameters. See HAS SIS ICD 1.0 Section 5.1.1 uint8_t has_status; //!< HASS - HAS Status (from HAS page header). See HAS SIS ICD 1.0 Section 3.1.1 uint8_t message_id; //!< MID - Message ID (from HAS page header). See HAS SIS ICD 1.0 Section 3.1 diff --git a/src/core/system_parameters/galileo_has_page.h b/src/core/system_parameters/galileo_has_page.h index 099ddd645..27da69f9b 100644 --- a/src/core/system_parameters/galileo_has_page.h +++ b/src/core/system_parameters/galileo_has_page.h @@ -39,6 +39,7 @@ public: std::string has_message_string; //!< HAS message content uint64_t time_stamp{}; //!< HAS page time stamp, in [s] + uint32_t tow{}; //!< HAS page time of week, in [s] // HAS page header uint8_t has_status{}; //!< HAS status From 657a7298f352276a147956f7a2a3c4f8eff5d997 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 25 May 2022 14:43:01 +0200 Subject: [PATCH 07/31] Compute PVT with E6 only and xml assistance --- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 11 +++++ src/algorithms/PVT/libs/rtklib_solver.cc | 48 +++++++++++++++++++ .../libs/rtklib/rtklib_conversions.cc | 4 ++ src/core/libs/gnss_sdr_supl_client.cc | 7 +++ 4 files changed, 70 insertions(+) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 83299a356..77468dcfe 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -651,6 +651,13 @@ rtklib_pvt_gs::~rtklib_pvt_gs() { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); + // Annotate as GPS week number + for (auto gal_eph_iter = d_internal_pvt_solver->galileo_ephemeris_map.begin(); + gal_eph_iter != d_internal_pvt_solver->galileo_ephemeris_map.end(); + ++gal_eph_iter) + { + gal_eph_iter->second.WN += 1024; + } xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", d_internal_pvt_solver->galileo_ephemeris_map); LOG(INFO) << "Saved Galileo E1 Ephemeris map data"; } @@ -2049,6 +2056,10 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item store_valid_observable = true; } } + if (std::string(in[i][epoch].Signal) == std::string("E6")) + { + store_valid_observable = true; + } if (store_valid_observable) { diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index bfa3bd52b..1c9c0b3ea 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -407,6 +407,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ bool band1 = false; bool band2 = false; bool gal_e5_is_e5b = false; + bool gal_e6 = false; for (gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); ++gnss_observables_iter) @@ -514,6 +515,48 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ gal_e5_is_e5b = true; } } + if (sig_ == "E6") + { + gal_e6 = true; + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) + { + bool found_E1_obs = false; + for (int i = 0; i < valid_obs; i++) + { + if (eph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN + NSATGPS + NSATGLO))) + { + d_obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(d_obs_data[i + glo_valid_obs], + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN, + 0); // Band 1 (E6) + found_E1_obs = true; + break; + } + } + if (!found_E1_obs) + { + // insert Galileo E6 obs as new obs and also insert its ephemeris + // convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + // convert observation from GNSS-SDR class to RTKLIB structure + const auto default_code_ = static_cast(CODE_NONE); + obsd_t newobs = {{0, 0}, '0', '0', {}, {}, + {default_code_, default_code_, default_code_}, + {}, {0.0, 0.0, 0.0}, {}}; + d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN, + 0); // Band 1 (E6) + // std::cout << "Week " << galileo_ephemeris_iter->second.WN << '\n'; + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } break; } case 'G': @@ -879,6 +922,11 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { for (int j = 0; j < NFREQ; j++) { + if (j == 0 && gal_e6) + { + // frq = 3 corresponds to E6 in that function + nav_data.lam[i][j] = satwavelen(i + 1, 3, &nav_data); + } if (j == 2 && gal_e5_is_e5b) { // frq = 4 corresponds to E5B in that function diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.cc b/src/algorithms/libs/rtklib/rtklib_conversions.cc index 45eacabcb..b7e50519c 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.cc +++ b/src/algorithms/libs/rtklib/rtklib_conversions.cc @@ -75,6 +75,10 @@ obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro { rtklib_obs.code[band] = static_cast(CODE_L7X); } + if (sig_ == "E6") + { + rtklib_obs.code[band] = static_cast(CODE_L6B); + } break; case 'R': rtklib_obs.sat = gnss_synchro.PRN + NSATGPS; diff --git a/src/core/libs/gnss_sdr_supl_client.cc b/src/core/libs/gnss_sdr_supl_client.cc index e079b0a9f..33a6969f0 100644 --- a/src/core/libs/gnss_sdr_supl_client.cc +++ b/src/core/libs/gnss_sdr_supl_client.cc @@ -414,6 +414,13 @@ bool Gnss_Sdr_Supl_Client::load_gal_ephemeris_xml(const std::string& file_name) gal_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", this->gal_ephemeris_map); LOG(INFO) << "Loaded Ephemeris map data with " << this->gal_ephemeris_map.size() << " satellites"; + // Convert to GPS week number + for (auto gal_eph_iter = this->gal_ephemeris_map.begin(); + gal_eph_iter != this->gal_ephemeris_map.end(); + ++gal_eph_iter) + { + gal_eph_iter->second.WN -= 1024; + } } catch (std::exception& e) { From ab4020178323e61e2e769f6cc4b55f4e91d118e6 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 25 May 2022 21:04:44 +0200 Subject: [PATCH 08/31] Improve loops --- src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 8 +++----- src/core/libs/gnss_sdr_supl_client.cc | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 77468dcfe..f44573db8 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -651,12 +651,10 @@ rtklib_pvt_gs::~rtklib_pvt_gs() { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); - // Annotate as GPS week number - for (auto gal_eph_iter = d_internal_pvt_solver->galileo_ephemeris_map.begin(); - gal_eph_iter != d_internal_pvt_solver->galileo_ephemeris_map.end(); - ++gal_eph_iter) + // Annotate as full GPS week number + for (auto& gal_eph_iter : d_internal_pvt_solver->galileo_ephemeris_map) { - gal_eph_iter->second.WN += 1024; + gal_eph_iter.second.WN += 1024; } xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", d_internal_pvt_solver->galileo_ephemeris_map); LOG(INFO) << "Saved Galileo E1 Ephemeris map data"; diff --git a/src/core/libs/gnss_sdr_supl_client.cc b/src/core/libs/gnss_sdr_supl_client.cc index 33a6969f0..e2e9a3c73 100644 --- a/src/core/libs/gnss_sdr_supl_client.cc +++ b/src/core/libs/gnss_sdr_supl_client.cc @@ -414,12 +414,10 @@ bool Gnss_Sdr_Supl_Client::load_gal_ephemeris_xml(const std::string& file_name) gal_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", this->gal_ephemeris_map); LOG(INFO) << "Loaded Ephemeris map data with " << this->gal_ephemeris_map.size() << " satellites"; - // Convert to GPS week number - for (auto gal_eph_iter = this->gal_ephemeris_map.begin(); - gal_eph_iter != this->gal_ephemeris_map.end(); - ++gal_eph_iter) + // Convert to full GPS week number + for (auto& gal_eph_iter : this->gal_ephemeris_map) { - gal_eph_iter->second.WN -= 1024; + gal_eph_iter.second.WN -= 1024; } } catch (std::exception& e) From 92b021f1b6855db2f9dbd2137809576e1ea5eda8 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 26 May 2022 10:02:58 +0200 Subject: [PATCH 09/31] Improve handling of E6 observables --- src/algorithms/PVT/libs/rtklib_solver.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index 1c9c0b3ea..cc0f96ac4 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -529,7 +529,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ d_obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(d_obs_data[i + glo_valid_obs], gnss_observables_iter->second, galileo_ephemeris_iter->second.WN, - 0); // Band 1 (E6) + 2); // Band E6 found_E1_obs = true; break; } @@ -547,7 +547,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, galileo_ephemeris_iter->second.WN, - 0); // Band 1 (E6) + 2); // Band E6 // std::cout << "Week " << galileo_ephemeris_iter->second.WN << '\n'; valid_obs++; } @@ -922,7 +922,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { for (int j = 0; j < NFREQ; j++) { - if (j == 0 && gal_e6) + if (j == 2 && gal_e6) { // frq = 3 corresponds to E6 in that function nav_data.lam[i][j] = satwavelen(i + 1, 3, &nav_data); From 934bbcaa459c8974104a2d8430cdb354b3db6ae1 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 30 May 2022 14:20:34 +0200 Subject: [PATCH 10/31] Add Galileo E6B observables in RINEX files if available --- src/algorithms/PVT/libs/rinex_printer.cc | 160 +++++++++++++++++++++-- 1 file changed, 146 insertions(+), 14 deletions(-) diff --git a/src/algorithms/PVT/libs/rinex_printer.cc b/src/algorithms/PVT/libs/rinex_printer.cc index 4b41dcd2a..af29e783b 100644 --- a/src/algorithms/PVT/libs/rinex_printer.cc +++ b/src/algorithms/PVT/libs/rinex_printer.cc @@ -112,7 +112,7 @@ Rinex_Printer::Rinex_Printer(int32_t conf_version, observationCode["GALILEO_E5_IQ"] = "8X"; // "8X" GALILEO E5 I+Q observationCode["GALILEO_E56_A"] = "6A"; // "6A" GALILEO E6 A observationCode["GALILEO_E56_B"] = "6B"; // "6B" GALILEO E6 B - observationCode["GALILEO_E56_B"] = "6C"; // "6C" GALILEO E6 C + observationCode["GALILEO_E56_C"] = "6C"; // "6C" GALILEO E6 C observationCode["GALILEO_E56_BC"] = "6X"; // "6X" GALILEO E6 B+C observationCode["GALILEO_E56_ABC"] = "6Z"; // "6Z" GALILEO E6 A+B+C observationCode["SBAS_L1_CA"] = "1C"; // "1C" SBAS L1 C/A @@ -621,10 +621,22 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons d_rinex_header_written = true; // do not write header anymore } break; + case 100: // Galileo E6B + if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) + { + const std::string gal_signal("E6"); + rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, gal_signal); + rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); + output_navfilename.push_back(navGalfilename); + log_rinex_nav(navGalFile, pvt_solver->galileo_ephemeris_map); + d_rinex_header_written = true; // do not write header anymore + } + break; case 101: // Galileo E1B + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time); + const std::string gal_signal("1B E6"); + rinex_obs_header(obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, rx_time, gal_signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); log_rinex_nav(navGalFile, pvt_solver->galileo_ephemeris_map); @@ -634,7 +646,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 102: // Galileo E5a + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - const std::string signal("5X"); + const std::string signal("5X E6"); rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); @@ -645,7 +657,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 103: // Galileo E5b + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - const std::string signal("7X"); + const std::string signal("7X E6"); rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); @@ -656,7 +668,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 104: // Galileo E1B + Galileo E5a + Galileo E6B if ((galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend())) { - const std::string gal_signal("1B 5X"); + const std::string gal_signal("1B 5X E6"); rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, gal_signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); @@ -667,7 +679,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 105: // Galileo E1B + Galileo E5b + Galileo E6B if ((galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend())) { - const std::string gal_signal("1B 7X"); + const std::string gal_signal("1B 7X E6"); rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, gal_signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); @@ -678,7 +690,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 106: // GPS L1 C/A + Galileo E1B + Galileo E6B if ((galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) and (gps_ephemeris_iter != pvt_solver->gps_ephemeris_map.cend())) { - const std::string gal_signal("1B"); + const std::string gal_signal("1B E6"); rinex_obs_header(obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, rx_time, gal_signal); rinex_nav_header(navMixFile, pvt_solver->gps_iono, pvt_solver->gps_utc_model, gps_ephemeris_iter->second, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navMixfilename); @@ -1077,10 +1089,22 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons } } break; + case 100: // Galileo E6B + if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) + { + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "E6"); + } + if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) + { + update_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); + update_obs_header(obsFile, pvt_solver->galileo_utc_model); + d_rinex_header_updated = true; + } + break; case 101: // Galileo E1B + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B"); + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B E6"); } if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) { @@ -1092,7 +1116,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 102: // Galileo E5a + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "5X"); + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "5X E6"); } if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) { @@ -1104,7 +1128,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 103: // Galileo E5b + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "5X"); + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "7X E6"); } if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) { @@ -1116,7 +1140,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 104: // Galileo E1B + Galileo E5a + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B 5X"); + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B 5X E6"); } if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) { @@ -1128,7 +1152,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons case 105: // Galileo E1B + Galileo E5b + Galileo E6B if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { - log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B 7X"); + log_rinex_obs(obsFile, galileo_ephemeris_iter->second, rx_time, gnss_observables_map, "1B 7X E6"); } if (!d_rinex_header_updated and (pvt_solver->galileo_utc_model.A0 != 0)) { @@ -1317,6 +1341,7 @@ void Rinex_Printer::log_rinex_nav_gal_nav(int type_of_rx, const std::mapsecond; @@ -8899,7 +8932,6 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& number_of_observations = number_of_observations + 4; } - line.clear(); signal_ = "7X"; const std::size_t found_7X = bands.find(signal_); if (found_7X != std::string::npos) @@ -8907,6 +8939,13 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& number_of_observations = number_of_observations + 4; } + signal_ = "E6"; + const std::size_t found_E6 = bands.find(signal_); + if (found_E6 != std::string::npos) + { + number_of_observations = number_of_observations + 4; + } + line.clear(); line += satelliteSystem.find("Galileo")->second; @@ -8961,6 +9000,22 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& line += observationCode["GALILEO_E5b_IQ"]; } + if (found_E6 != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E56_B"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E56_B"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E56_B"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E56_B"]; + } + line += std::string(60 - line.size(), ' '); line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); Rinex_Printer::lengthCheck(line); @@ -11586,6 +11641,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep std::map observablesE1B; std::map observablesE5A; std::map observablesE5B; + std::map observablesE6B; std::map::const_iterator observables_iter; for (observables_iter = observables.cbegin(); @@ -11606,10 +11662,15 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep { observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } + if ((system_ == "E") && (sig_ == "E6")) + { + observablesE6B.insert(std::pair(observables_iter->first, observables_iter->second)); + } } const std::size_t found_1B = galileo_bands.find("1B"); const std::size_t found_E5a = galileo_bands.find("5X"); const std::size_t found_E5b = galileo_bands.find("7X"); + const std::size_t found_E6b = galileo_bands.find("E6"); std::multimap total_map; std::set available_prns; @@ -11706,6 +11767,23 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& ep total_map.insert(std::pair(prn_, observables_iter->second)); } } + + if (found_E6b != std::string::npos) + { + for (observables_iter = observablesE6B.cbegin(); + observables_iter != observablesE6B.cend(); + observables_iter++) + { + const uint32_t prn_ = observables_iter->second.PRN; + total_map.insert(std::pair(prn_, observables_iter->second)); + it = available_prns.find(prn_); + if (it == available_prns.end()) + { + available_prns.insert(prn_); + } + } + } + const int32_t numSatellitesObserved = available_prns.size(); line += Rinex_Printer::rightJustify(std::to_string(numSatellitesObserved), 3); // Receiver clock offset (optional) @@ -11834,6 +11912,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep std::map observablesE1B; std::map observablesE5A; std::map observablesE5B; + std::map observablesE6B; std::map::const_iterator observables_iter; for (observables_iter = observables.cbegin(); @@ -11854,6 +11933,10 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep { observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } + if ((system_ == "E") && (sig_ == "E6")) + { + observablesE6B.insert(std::pair(observables_iter->first, observables_iter->second)); + } if ((system_ == "G") && (sig_ == "1C")) { observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); @@ -11902,6 +11985,19 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep } } + for (observables_iter = observablesE6B.cbegin(); + observables_iter != observablesE6B.cend(); + observables_iter++) + { + const uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + const int32_t numGalSatellitesObserved = available_gal_prns.size(); const int32_t numGpsSatellitesObserved = observablesG1C.size(); const int32_t numSatellitesObserved = numGalSatellitesObserved + numGpsSatellitesObserved; @@ -12107,6 +12203,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& e std::map observablesE1B; std::map observablesE5A; std::map observablesE5B; + std::map observablesE6B; std::map::const_iterator observables_iter; for (observables_iter = observables.cbegin(); @@ -12127,6 +12224,10 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& e { observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } + if ((system_ == "E") && (sig_ == "E6")) + { + observablesE6B.insert(std::pair(observables_iter->first, observables_iter->second)); + } if ((system_ == "G") && (sig_ == "2S")) { observablesG2S.insert(std::pair(observables_iter->first, observables_iter->second)); @@ -12181,6 +12282,19 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_CNAV_Ephemeris& e } } + for (observables_iter = observablesE6B.cbegin(); + observables_iter != observablesE6B.cend(); + observables_iter++) + { + const uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + for (observables_iter = observablesG2S.cbegin(); observables_iter != observablesG2S.cend(); observables_iter++) @@ -12405,6 +12519,7 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep std::map observablesE1B; std::map observablesE5A; std::map observablesE5B; + std::map observablesE6B; std::map::const_iterator observables_iter; for (observables_iter = observables.cbegin(); @@ -12425,6 +12540,10 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep { observablesE5B.insert(std::pair(observables_iter->first, observables_iter->second)); } + if ((system_ == "E") && (sig_ == "E6")) + { + observablesE6B.insert(std::pair(observables_iter->first, observables_iter->second)); + } if ((system_ == "G") && (sig_ == "2S")) { observablesG2S.insert(std::pair(observables_iter->first, observables_iter->second)); @@ -12483,6 +12602,19 @@ void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_ep } } + for (observables_iter = observablesE6B.cbegin(); + observables_iter != observablesE6B.cend(); + observables_iter++) + { + const uint32_t prn_ = observables_iter->second.PRN; + total_gal_map.insert(std::pair(prn_, observables_iter->second)); + it = available_gal_prns.find(prn_); + if (it == available_gal_prns.end()) + { + available_gal_prns.insert(prn_); + } + } + for (observables_iter = observablesG1C.cbegin(); observables_iter != observablesG1C.cend(); observables_iter++) From b347bcbb79500e8a92d02bfc129b862f1257ea0b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 30 May 2022 14:42:57 +0200 Subject: [PATCH 11/31] Fix Gal E1/E6 RINEX reporting --- src/algorithms/PVT/libs/rinex_printer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/PVT/libs/rinex_printer.cc b/src/algorithms/PVT/libs/rinex_printer.cc index af29e783b..4a5e8c20c 100644 --- a/src/algorithms/PVT/libs/rinex_printer.cc +++ b/src/algorithms/PVT/libs/rinex_printer.cc @@ -636,7 +636,7 @@ void Rinex_Printer::print_rinex_annotation(const Rtklib_Solver* pvt_solver, cons if (galileo_ephemeris_iter != pvt_solver->galileo_ephemeris_map.cend()) { const std::string gal_signal("1B E6"); - rinex_obs_header(obsFile, gps_ephemeris_iter->second, galileo_ephemeris_iter->second, rx_time, gal_signal); + rinex_obs_header(obsFile, galileo_ephemeris_iter->second, rx_time, gal_signal); rinex_nav_header(navGalFile, pvt_solver->galileo_iono, pvt_solver->galileo_utc_model); output_navfilename.push_back(navGalfilename); log_rinex_nav(navGalFile, pvt_solver->galileo_ephemeris_map); From e074883f06f11fad62d2d9c084461cedfb869c59 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 7 Jun 2022 09:19:29 +0200 Subject: [PATCH 12/31] Adding a native AD936x custom signal source, still not usable --- CMakeLists.txt | 5 + .../gnuradio_blocks/CMakeLists.txt | 4 + .../gnuradio_blocks/ad936x_iio_source.cc | 96 +++++++++++++++++ .../gnuradio_blocks/ad936x_iio_source.h | 100 ++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc create mode 100644 src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a813ad30..a96d63e93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,8 @@ option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requ option(ENABLE_PLUTOSDR "Enable the use of ADALM-PLUTO Evaluation Boards (Analog Devices Inc.), requires gr-iio" OFF) +option(ENABLE_AD936X_SDR "Enable the use of AD936X front-ends using libiio, requires libiio" OFF) + option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF) option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) @@ -3055,6 +3057,7 @@ set_package_properties(LIBAD9361 PROPERTIES ) if(NOT LIBAD9361_FOUND) set(ENABLE_AD9361 OFF) + set(ENABLE_AD936X_SDR OFF) set(ENABLE_FMCOMMS2 OFF) endif() if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) @@ -3094,6 +3097,7 @@ if(ENABLE_AD9361 OR ENABLE_FMCOMMS2) message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") if(ENABLE_PACKAGING) set(ENABLE_AD9361 OFF) + set(ENABLE_AD936X_SDR OFF) set(ENABLE_FMCOMMS2 OFF) else() message(FATAL_ERROR "libiio is required for building gnss-sdr with -DENABLE_AD9361=ON.") @@ -3337,6 +3341,7 @@ add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. R add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") +add_feature_info(ENABLE_AD936X_SDR ENABLE_AD9361 "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") add_feature_info(ENABLE_ARRAY ENABLE_ARRAY "Enables Raw_Array_Signal_Source and Array_Signal_Conditioner for using CTTC's antenna array. Requires gr-dbfcttc.") diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index 96fa168c2..6172102bc 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -12,6 +12,10 @@ if(ENABLE_RAW_UDP AND PCAP_FOUND) set(OPT_DRIVER_HEADERS gr_complex_ip_packet_source.h) endif() +if(ENABLE_AD936X_SDR) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gr_complex_ip_packet_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h) +endif() set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES fifo_reader.cc diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc new file mode 100644 index 000000000..efee6ad49 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -0,0 +1,96 @@ +/*! + * \file ad936x_iio_source.cc + * + * \brief Unpacks capture files in the LabSat 2 (ls2), LabSat 3 (ls3), or LabSat + * 3 Wideband (LS3W) formats. + * \author Javier Arribas jarribas (at) cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#include "ad936x_iio_source.h" +#include "INIReader.h" +#include "command_event.h" +#include "gnss_sdr_make_unique.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +ad936x_iio_source_sptr ad936x_iio_make_source_sptr(Concurrent_Queue *queue, + std::string pluto_device_uri, + std::string board_type, + long long bandwidth_, + long long sample_rate_, + std::vector ch_list, + std::vector ch_gain_mode, + std::vector ch_gain_db, + std::vector ch_freq_hz, + int ch_sample_size, + int ch_sample_bits_shift) +{ + return ad936x_iio_source_sptr(new ad936x_iio_source(*queue, + pluto_device_uri, + board_type, + bandwidth_, + sample_rate_, + ch_list, + ch_gain_mode, + ch_gain_db, + ch_freq_hz, + ch_sample_size, + ch_sample_bits_shift)); +} + + +ad936x_iio_source::ad936x_iio_source(Concurrent_Queue *queue, + std::string pluto_device_uri, + std::string board_type, + long long bandwidth_, + long long sample_rate_, + std::vector ch_list, + std::vector ch_gain_mode, + std::vector ch_gain_db, + std::vector ch_freq_hz, + int ch_sample_size, + int ch_sample_bits_shift) : gr::block("ad936x_iio_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 3, sizeof(gr_complex))) +{ +} + + +ad936x_iio_source::~ad936x_iio_source() +{ +} + + +int ad936x_iio_source::general_work(int noutput_items, + __attribute__((unused)) gr_vector_int &ninput_items, + __attribute__((unused)) gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + std::vector out; + for (auto &output_item : output_items) + { + out.push_back(reinterpret_cast(output_item)); + } + std::cout << "Warning!!\n"; + return 0; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h new file mode 100644 index 000000000..aec4a3c56 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h @@ -0,0 +1,100 @@ +/*! + * \file ad936x_iio_source.h + * + * \brief signal source to receive samples from the AD936x FE family over libiio, including special custom functionalities in FPGA firmware. + * \author Javier Arribas jarribas (at) cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_AD9361_IIO_SOURCE_H +#define GNSS_SDR_AD9361_IIO_SOURCE_H + +#include "concurrent_queue.h" +#include "gnss_block_interface.h" +#include +#include +#include +#include //multichip sync and high level functions +#include +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_gnuradio_blocks + * \{ */ + + +class ad936x_iio_source; + +using ad936x_iio_source_sptr = gnss_shared_ptr; + +ad936x_iio_source_sptr ad936x_iio_make_source_sptr( + Concurrent_Queue *queue, + std::string pluto_device_uri, + std::string board_type, + long long bandwidth_, + long long sample_rate_, + std::vector ch_list, + std::vector ch_gain_mode, + std::vector ch_gain_db, + std::vector ch_freq_hz, + int ch_sample_size, + int ch_sample_bits_shift); + +/*! + * \brief This class implements conversion between Labsat 2, 3 and 3 Wideband + * formats to gr_complex + */ +class ad936x_iio_source : public gr::block +{ +public: + ~ad936x_iio_source(); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + +private: + friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr( + Concurrent_Queue *queue, + std::string pluto_device_uri, + std::string board_type, + long long bandwidth_, + long long sample_rate_, + std::vector ch_list, + std::vector ch_gain_mode, + std::vector ch_gain_db, + std::vector ch_freq_hz, + int ch_sample_size, + int ch_sample_bits_shift); + + ad936x_iio_source(Concurrent_Queue *queue, + std::string pluto_device_uri, + std::string board_type, + long long bandwidth_, + long long sample_rate_, + std::vector ch_list, + std::vector ch_gain_mode, + std::vector ch_gain_db, + std::vector ch_freq_hz, + int ch_sample_size, + int ch_sample_bits_shift); +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_AD9361_IIO_SOURCE_H From 0a346c301767a593cc1bed73b79a38ee1bbc9a80 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Wed, 8 Jun 2022 10:21:05 +0200 Subject: [PATCH 13/31] Fix segmentation fault in file_timestamp_signal_source --- .../adapters/file_timestamp_signal_source.cc | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc index 32d27ac19..8e17180f8 100644 --- a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc @@ -50,21 +50,48 @@ gnss_shared_ptr FileTimestampSignalSource::source() const { return ti void FileTimestampSignalSource::create_file_source_hook() { - if (is_complex() == false) + int source_items_to_samples = 1; + bool is_complex = false; + + if (item_type().compare("ibyte") == 0) { + source_items_to_samples = 1; + } + else if (item_type().compare("byte") == 0) + { + source_items_to_samples = 1; + } + else if (item_type().compare("short") == 0) + { + source_items_to_samples = 1; + } + else if (item_type().compare("ishort") == 0) + { + source_items_to_samples = 1; + } + else if (item_type().compare("gr_complex") == 0) + { + source_items_to_samples = 1; + is_complex = true; + } + + if (is_complex == false) + { + std::cout << "A : " << std::get<0>(itemTypeToSize()) << "\n"; timestamp_block_ = gnss_sdr_make_Timestamp( std::get<0>(itemTypeToSize()), timestamp_file_, timestamp_clock_offset_ms_, - source_item_size() * 2); + source_items_to_samples * 2); } else { + std::cout << "B : " << std::get<0>(itemTypeToSize()) << "\n"; timestamp_block_ = gnss_sdr_make_Timestamp( std::get<0>(itemTypeToSize()), timestamp_file_, timestamp_clock_offset_ms_, - source_item_size()); + source_items_to_samples); } DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")"; } From a7147702bc2d2ddd9c61b1e90a8f991886bade68 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Thu, 30 Jun 2022 10:38:29 +0200 Subject: [PATCH 14/31] Bug fix: PVT does not resolve position anymore after a loss of samples event --- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 25 +++++++++++++++---- .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 3 ++- .../gnuradio_blocks/hybrid_observables_gs.cc | 20 ++++++++++++++- .../gnuradio_blocks/hybrid_observables_gs.h | 1 + 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 9ec599576..6a4f82616 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -166,11 +166,13 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, d_flag_monitor_pvt_enabled(conf_.monitor_enabled), d_flag_monitor_ephemeris_enabled(conf_.monitor_ephemeris_enabled), d_show_local_time_zone(conf_.show_local_time_zone), - d_waiting_obs_block_rx_clock_offset_correction_msg(false), + d_timestamp_rx_clock_offset_correction_msg_ms(0LL), d_enable_rx_clock_correction(conf_.enable_rx_clock_correction), d_an_printer_enabled(conf_.an_output_enabled), d_log_timetag(conf_.log_source_timetag) { + //debug + d_pvt_errors_counter = 0; // Send feedback message to observables block with the receiver clock offset this->message_port_register_out(pmt::mp("pvt_to_observables")); // Experimental: VLT commands from PVT to tracking channels @@ -2168,18 +2170,18 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (fabs(Rx_clock_offset_s) * 1000.0 > d_max_obs_block_rx_clock_offset_ms) { - if (!d_waiting_obs_block_rx_clock_offset_correction_msg) + //check if the message was just sent to not duplicate it while it is being applied + if ((d_local_counter_ms - d_timestamp_rx_clock_offset_correction_msg_ms) > 1000) { this->message_port_pub(pmt::mp("pvt_to_observables"), pmt::make_any(Rx_clock_offset_s)); - d_waiting_obs_block_rx_clock_offset_correction_msg = true; - LOG(INFO) << "Sent clock offset correction to observables: " << Rx_clock_offset_s << "[s]"; + d_timestamp_rx_clock_offset_correction_msg_ms = d_local_counter_ms; + LOG(INFO) << "PVT: Sent clock offset correction to observables: " << Rx_clock_offset_s << "[s]"; } } else { if (d_enable_rx_clock_correction == true) { - d_waiting_obs_block_rx_clock_offset_correction_msg = false; d_gnss_observables_map_t0 = d_gnss_observables_map_t1; apply_rx_clock_offset(d_gnss_observables_map, Rx_clock_offset_s); d_gnss_observables_map_t1 = d_gnss_observables_map; @@ -2209,6 +2211,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } else { + d_pvt_errors_counter = 0; d_rx_time = d_gnss_observables_map.begin()->second.RX_time; current_RX_time_ms = static_cast(d_rx_time * 1000.0); if (current_RX_time_ms % d_output_rate_ms == 0) @@ -2221,6 +2224,18 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } } } + else + { + //sanity check: If the PVT solver is getting 100 consecutive errors, send a reset command to observables block + d_pvt_errors_counter++; + if (d_pvt_errors_counter >= 100) + { + int command = 1; + this->message_port_pub(pmt::mp("pvt_to_observables"), pmt::make_any(command)); + LOG(INFO) << "PVT: Number of consecutive position solver error reached, Sent reset to observables."; + d_pvt_errors_counter = 0; + } + } // compute on the fly PVT solution if (flag_compute_pvt_output == true) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index bfd53db63..c9a627e72 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -282,7 +282,8 @@ private: bool d_flag_monitor_pvt_enabled; bool d_flag_monitor_ephemeris_enabled; bool d_show_local_time_zone; - bool d_waiting_obs_block_rx_clock_offset_correction_msg; + uint64_t d_timestamp_rx_clock_offset_correction_msg_ms; + uint32_t d_pvt_errors_counter; bool d_enable_rx_clock_correction; bool d_enable_has_messages; bool d_an_printer_enabled; diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc index 82b86fc9e..0778dd5c3 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc @@ -226,6 +226,25 @@ void hybrid_observables_gs::msg_handler_pvt_to_observables(const pmt::pmt_t &msg LOG(INFO) << "Corrected new RX Time offset: " << static_cast(round(new_rx_clock_offset_s * 1000.0)) << "[ms]"; } + if (pmt::any_ref(msg).type().hash_code() == d_int_type_hash_code) + { + const auto command_from_pvt = wht::any_cast(pmt::any_ref(msg)); + switch (command_from_pvt) + { + case 1: //reset TOW + d_T_rx_TOW_ms = 0; + d_last_rx_clock_round20ms_error = 0; + d_T_rx_TOW_set = false; + for (uint32_t n = 0; n < d_nchannels_out; n++) + { + d_gnss_synchro_history->clear(n); + } + LOG(INFO) << "Received reset observables TOW command from PVT"; + break; + default: + break; + } + } } catch (const wht::bad_any_cast &e) { @@ -786,7 +805,6 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused) } epoch_data[n] = interpolated_gnss_synchro; } - if (d_T_rx_TOW_set) { update_TOW(epoch_data); diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h index a6966b5d6..5c4863c7c 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h @@ -70,6 +70,7 @@ private: explicit hybrid_observables_gs(const Obs_Conf& conf_); const size_t d_double_type_hash_code = typeid(double).hash_code(); + const size_t d_int_type_hash_code = typeid(int).hash_code(); void msg_handler_pvt_to_observables(const pmt::pmt_t& msg); double compute_T_rx_s(const Gnss_Synchro& a) const; From 5292f0d8fc36384afaad98bb4fba86a6177aeb12 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Thu, 30 Jun 2022 12:31:25 +0200 Subject: [PATCH 15/31] Improve PVT error detection --- src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index bb989eb96..dca10600a 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -2128,6 +2128,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item // #### solve PVT and store the corrected observable set if (d_internal_pvt_solver->get_PVT(d_gnss_observables_map, false)) { + d_pvt_errors_counter = 0; // Reset consecutive PVT error counter const double Rx_clock_offset_s = d_internal_pvt_solver->get_time_offset_s(); // **************** time tags **************** @@ -2211,7 +2212,6 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } else { - d_pvt_errors_counter = 0; d_rx_time = d_gnss_observables_map.begin()->second.RX_time; current_RX_time_ms = static_cast(d_rx_time * 1000.0); if (current_RX_time_ms % d_output_rate_ms == 0) From 6311530cb4a8072c640cb5d6b200d65cd37958c3 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Sun, 14 Aug 2022 12:10:59 +0200 Subject: [PATCH 16/31] Adding new Ad936x custom signal source, initial commit, experimental --- .../signal_source/adapters/CMakeLists.txt | 6 + .../adapters/ad936x_custom_signal_source.cc | 325 +++++ .../adapters/ad936x_custom_signal_source.h | 118 ++ .../gnuradio_blocks/CMakeLists.txt | 7 + .../gnuradio_blocks/ad936x_iio_source.cc | 262 +++- .../gnuradio_blocks/ad936x_iio_source.h | 115 +- .../signal_source/libs/CMakeLists.txt | 18 +- .../signal_source/libs/ad936x_iio_custom.cc | 1195 +++++++++++++++++ .../signal_source/libs/ad936x_iio_custom.h | 144 ++ .../signal_source/libs/ad936x_iio_samples.cc | 26 + .../signal_source/libs/ad936x_iio_samples.h | 41 + .../signal_source/libs/pps_samplestamp.h | 20 + src/algorithms/signal_source/libs/ppstcprx.cc | 154 +++ src/algorithms/signal_source/libs/ppstcprx.h | 34 + src/core/receiver/concurrent_queue.h | 12 + src/core/receiver/gnss_block_factory.cc | 7 + 16 files changed, 2405 insertions(+), 79 deletions(-) create mode 100644 src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc create mode 100644 src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h create mode 100644 src/algorithms/signal_source/libs/ad936x_iio_custom.cc create mode 100644 src/algorithms/signal_source/libs/ad936x_iio_custom.h create mode 100644 src/algorithms/signal_source/libs/ad936x_iio_samples.cc create mode 100644 src/algorithms/signal_source/libs/ad936x_iio_samples.h create mode 100644 src/algorithms/signal_source/libs/pps_samplestamp.h create mode 100644 src/algorithms/signal_source/libs/ppstcprx.cc create mode 100644 src/algorithms/signal_source/libs/ppstcprx.h diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index e99748358..40e72049c 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -21,6 +21,12 @@ if(ENABLE_PLUTOSDR) ############################################## set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} plutosdr_signal_source.cc) set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} plutosdr_signal_source.h) + + ############################################## + # CUSTOM AD936X IIO SOURCE + ############################################## + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_custom_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h) endif() diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc new file mode 100644 index 000000000..91f11b410 --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc @@ -0,0 +1,325 @@ +/*! + * \file ad936x_custom_signal_source.cc + * \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#include "ad936x_custom_signal_source.h" +#include "configuration_interface.h" +#include "gnss_frequencies.h" +#include "gnss_sdr_string_literals.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include + +using namespace std::string_literals; + +Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_stream, + unsigned int out_stream, + Concurrent_Queue* queue __attribute__((unused))) + : SignalSourceBase(configuration, role, "Ad936x_Custom_Signal_Source"s), + in_stream_(in_stream), + out_stream_(out_stream), + item_type_(configuration->property(role + ".item_type", std::string("gr_complex"))), + samples_(configuration->property(role + ".samples", int64_t(0))), + dump_(configuration->property(role + ".dump", false)), + dump_filename_(configuration->property(role + ".dump_filename", std::string("./data/signal_source.dat"))), + pluto_uri_(configuration->property(role + ".pluto_uri", std::string("local"))), + board_type_(configuration->property(role + ".board_type", std::string("single_ad9361"))), + sample_rate_(configuration->property(role + ".sampling_frequency", 4.0e6)), + bandwidth_(configuration->property(role + ".bandwidth", configuration->property(role + ".sampling_frequency", 4.0e6) / 1.1)), + freq_(configuration->property(role + ".freq", FREQ1)), + freq_2ch(configuration->property(role + ".freq_2ch", FREQ1)), + rf_port_select_(configuration->property(role + ".rf_port_select", std::string("A_BALANCED"))), + rf_filter(configuration->property(role + ".rf_filter", std::string("none"))), + gain_mode_rx0_(configuration->property(role + ".gain_mode_rx0", std::string("slow_attack"))), + gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", std::string("slow_attack"))), + rf_gain_rx0_(configuration->property(role + ".gain_rx0", 40.0)), + rf_gain_rx1_(configuration->property(role + ".gain_rx1", 40.0)), + enable_ch0(configuration->property(role + ".enable_ch0", true)), + enable_ch1(configuration->property(role + ".enable_ch1", false)), + PPS_mode_(configuration->property(role + ".PPS_mode", false)), + fe_ip_(configuration->property(role + ".fe_ip", std::string("192.168.2.1"))), + fe_ctlport_(configuration->property(role + ".fe_ctlport", int32_t(10000))), + ssize_(configuration->property(role + ".ssize", int32_t(16))), + bshift_(configuration->property(role + ".bshift", int64_t(0))), + spattern_(configuration->property(role + ".spattern", false)), + inverted_spectrum_ch0_(configuration->property(role + ".inverted_spectrum_ch0", false)), + inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false)) + + +{ + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + // 1. Make the driver instance + bool customsamplesize = false; + if (ssize_ != 16 or spattern_ == true) customsamplesize = true; + + ad936x_iio_source = ad936x_iio_make_source_sptr( + pluto_uri_, + board_type_, + bandwidth_, + sample_rate_, + freq_, + rf_port_select_, + rf_filter, + gain_mode_rx0_, + gain_mode_rx1_, + rf_gain_rx0_, + rf_gain_rx1_, + enable_ch0, + enable_ch1, + freq_2ch, + PPS_mode_, + customsamplesize, + fe_ip_, + fe_ctlport_, + ssize_, + bshift_, + spattern_); + + n_channels = 1; + if (enable_ch0 == true and enable_ch1 == true) + { + n_channels = 2; + } + + for (int n = 0; n < n_channels; n++) + { + if (ssize_ == 16) + { + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make()); + } + else if (ssize_ == 8) + { + gr_interleaved_char_to_complex_.push_back(gr::blocks::interleaved_char_to_complex::make()); + } + else if (ssize_ == 4) + { + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false)); + unpack_byte_fourbits.push_back(make_unpack_byte_4bit_samples()); + } + else if (ssize_ == 2) + { + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false)); + unpack_byte_twobits.push_back(make_unpack_byte_2bit_cpx_samples()); + } + } + } + else + { + LOG(ERROR) << item_type_ << " unrecognized item type"; + exit(1); + } + + + if (dump_) + { + for (int n = 0; n < n_channels; n++) + { + DLOG(INFO) << "Dumping output into file " << (dump_filename_ + "c_h" + std::to_string(n) + ".bin"); + sink_.emplace_back(gr::blocks::file_sink::make(item_size_, (dump_filename_ + "_ch" + std::to_string(n) + ".bin").c_str())); + } + } + + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) +{ + for (int n = 0; n < n_channels; n++) + { + if (ssize_ == 16) + { + top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 8) + { + top_block->connect(ad936x_iio_source, n, gr_interleaved_char_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 4) + { + top_block->connect(ad936x_iio_source, n, unpack_byte_fourbits.at(n), 0); + top_block->connect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 2) + { + top_block->connect(ad936x_iio_source, n, unpack_byte_twobits.at(n), 0); + top_block->connect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else + { + top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } +} + + +void Ad936xCustomSignalSource::disconnect(gr::top_block_sptr top_block) +{ + for (int n = 0; n < n_channels; n++) + { + if (ssize_ == 16) + { + top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; + if (dump_) + { + top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 8) + { + top_block->disconnect(ad936x_iio_source, n, gr_interleaved_char_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n; + if (dump_) + { + top_block->disconnect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 4) + { + top_block->disconnect(ad936x_iio_source, n, unpack_byte_fourbits.at(n), 0); + top_block->disconnect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else if (ssize_ == 2) + { + top_block->disconnect(ad936x_iio_source, n, unpack_byte_twobits.at(n), 0); + top_block->disconnect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; + if (dump_) + { + top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + else + { + top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; + if (dump_) + { + top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } +} + + +gr::basic_block_sptr Ad936xCustomSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return {}; +} + + +gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block() +{ + if (ssize_ == 16) + { + return gr_interleaved_short_to_complex_.at(0); + } + else if (ssize_ == 8) + { + return gr_interleaved_char_to_complex_.at(0); + } + else if (ssize_ == 4) + { + return gr_interleaved_short_to_complex_.at(0); + } + else if (ssize_ == 2) + { + return gr_interleaved_short_to_complex_.at(0); + } + else + { + return gr_interleaved_short_to_complex_.at(0); + } +} + +gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block(int RF_channel) +{ + if (ssize_ == 16) + { + return gr_interleaved_short_to_complex_.at(RF_channel); + } + else if (ssize_ == 8) + { + return gr_interleaved_char_to_complex_.at(RF_channel); + } + else if (ssize_ == 4) + { + return gr_interleaved_short_to_complex_.at(RF_channel); + } + else if (ssize_ == 2) + { + return gr_interleaved_short_to_complex_.at(RF_channel); + } + else + { + return gr_interleaved_short_to_complex_.at(RF_channel); + } +} diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h new file mode 100644 index 000000000..cc9abb82b --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h @@ -0,0 +1,118 @@ +/*! + * \file ad936x_custom_signal_source.h + * \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H +#define GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H + +#include "ad936x_iio_source.h" +#include "concurrent_queue.h" +#include "conjugate_cc.h" +#include "signal_source_base.h" +#include "unpack_byte_2bit_cpx_samples.h" +#include "unpack_byte_4bit_samples.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +/*! + * \brief This class instantiates the Ad936xCustom gnuradio signal source. + * It has support also for a customized Ad936xCustom firmware and signal source to support PPS samplestamp reading. + */ +class Ad936xCustomSignalSource : public SignalSourceBase +{ +public: + Ad936xCustomSignalSource(const ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, Concurrent_Queue* queue); + + ~Ad936xCustomSignalSource() = 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; + gr::basic_block_sptr get_right_block(int RF_channel) override; + +private: + unsigned int in_stream_; + unsigned int out_stream_; + gr::block_sptr ad936x_iio_source; + std::vector sink_; + std::vector filename_vec_; + + std::vector gr_interleaved_short_to_complex_; + std::vector gr_interleaved_char_to_complex_; + std::vector unpack_byte_fourbits; + std::vector unpack_byte_twobits; + + + std::string item_type_; + size_t item_size_; + int64_t samples_; + bool dump_; + std::string dump_filename_; + + // Front-end settings + std::string pluto_uri_; + std::string board_type_; + long long sample_rate_; + long long bandwidth_; + long long freq_; + long long freq_2ch; + std::string rf_port_select_; + std::string rf_filter; + std::string gain_mode_rx0_; + std::string gain_mode_rx1_; + double rf_gain_rx0_; + double rf_gain_rx1_; + bool enable_ch0; + bool enable_ch1; + bool PPS_mode_; + std::string fe_ip_; + int fe_ctlport_; + int ssize_; + int bshift_; + bool spattern_; + bool inverted_spectrum_ch0_; + bool inverted_spectrum_ch1_; + + + int n_channels; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index c1198c08b..b09f94cca 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -17,6 +17,13 @@ if(ENABLE_AD936X_SDR) set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h) endif() + +if(ENABLE_PLUTOSDR) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_iio_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h) +endif() + + set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES fifo_reader.cc unpack_byte_2bit_samples.cc diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index efee6ad49..f19a7e0a3 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -1,16 +1,14 @@ /*! * \file ad936x_iio_source.cc - * - * \brief Unpacks capture files in the LabSat 2 (ls2), LabSat 3 (ls3), or LabSat - * 3 Wideband (LS3W) formats. - * \author Javier Arribas jarribas (at) cttc.es + * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- * * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -19,12 +17,13 @@ #include "ad936x_iio_source.h" #include "INIReader.h" +#include "ad936x_iio_samples.h" #include "command_event.h" #include "gnss_sdr_make_unique.h" +#include "pps_samplestamp.h" #include #include #include -#include #include #include #include @@ -33,64 +32,245 @@ #include -ad936x_iio_source_sptr ad936x_iio_make_source_sptr(Concurrent_Queue *queue, - std::string pluto_device_uri, - std::string board_type, +ad936x_iio_source_sptr ad936x_iio_make_source_sptr( + std::string pluto_uri_, + std::string board_type_, long long bandwidth_, long long sample_rate_, - std::vector ch_list, - std::vector ch_gain_mode, - std::vector ch_gain_db, - std::vector ch_freq_hz, - int ch_sample_size, - int ch_sample_bits_shift) + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch, + bool ppsmode_, + bool customsamplesize_, + std::string fe_ip_, + int fe_ctlport_, + int ssize_, + int bshift_, + bool spattern_) { - return ad936x_iio_source_sptr(new ad936x_iio_source(*queue, - pluto_device_uri, - board_type, + return ad936x_iio_source_sptr(new ad936x_iio_source( + pluto_uri_, + board_type_, bandwidth_, sample_rate_, - ch_list, - ch_gain_mode, - ch_gain_db, - ch_freq_hz, - ch_sample_size, - ch_sample_bits_shift)); + freq_, + rf_port_select_, + rf_filter, + gain_mode_rx0_, + gain_mode_rx1_, + rf_gain_rx0_, + rf_gain_rx1_, + enable_ch0, + enable_ch1, + freq_2ch, + ppsmode_, + customsamplesize_, + fe_ip_, + fe_ctlport_, + ssize_, + bshift_, + spattern_)); } -ad936x_iio_source::ad936x_iio_source(Concurrent_Queue *queue, - std::string pluto_device_uri, - std::string board_type, +ad936x_iio_source::ad936x_iio_source( + std::string pluto_uri_, + std::string board_type_, long long bandwidth_, long long sample_rate_, - std::vector ch_list, - std::vector ch_gain_mode, - std::vector ch_gain_db, - std::vector ch_freq_hz, - int ch_sample_size, - int ch_sample_bits_shift) : gr::block("ad936x_iio_source", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(1, 3, sizeof(gr_complex))) + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch, + bool ppsmode_, + bool customsamplesize_, + std::string fe_ip_, + int fe_ctlport_, + int ssize_, + int bshift_, + bool spattern_) : gr::block("ad936x_iio_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 4, sizeof(int16_t))) { -} + ad936x_custom = std::make_unique(0, 0); + try + { + if (ad936x_custom->initialize_device(pluto_uri_, board_type_) == true) + { + //configure channels + if (ad936x_custom->init_config_ad9361_rx(bandwidth_, + sample_rate_, + freq_, + rf_port_select_, + rf_filter, + gain_mode_rx0_, + gain_mode_rx1_, + rf_gain_rx0_, + rf_gain_rx1_, + enable_ch0, + enable_ch1, + freq_2ch) == true) + { + std::cout << "ad936x_iio_source HW configured OK!\n"; + //PPS FPGA Samplestamp information from TCP server + pps_rx = std::make_shared(); + ppsqueue = std::shared_ptr>(new Concurrent_Queue()); + + pps_rx->set_pps_samplestamp_queue(ppsqueue); + ad936x_custom->set_pps_samplestamp_queue(ppsqueue); + + //start PPS RX thread + if (ppsmode_ == true or customsamplesize_ == true) + { + pps_rx_thread = std::thread(&pps_tcp_rx::receive_pps, pps_rx, fe_ip_, fe_ctlport_); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + //configure custom FPGA options + switch (ssize_) + { + case 16: + { + std::cout << "FPGA sample size set to 16 bits per sample.\n"; + if (pps_rx->send_cmd("ssize=16\n") == false) std::cout << "cmd send error!\n"; + break; + } + case 8: + { + std::cout << "FPGA sample size set to 8 bits per sample.\n"; + if (pps_rx->send_cmd("ssize=8\n") == false) std::cout << "cmd send error!\n"; + break; + } + case 4: + { + std::cout << "FPGA sample size set to 4 bits per sample.\n"; + if (pps_rx->send_cmd("ssize=4\n") == false) std::cout << "cmd send error!\n"; + break; + } + case 2: + { + std::cout << "FPGA sample size set to 2 bits per sample.\n"; + if (pps_rx->send_cmd("ssize=2\n") == false) std::cout << "cmd send error!\n"; + break; + } + default: + { + std::cout << "WARNING: Unsupported ssize. FPGA sample size set to 16 bits per sample.\n"; + if (pps_rx->send_cmd("ssize=16") == false) std::cout << "cmd send error!\n"; + } + } + + if (bshift_ >= 0 and bshift_ <= 14) + { + std::cout << "FPGA sample bits shift left set to " + std::to_string(bshift_) + " positions.\n"; + if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) std::cout << "cmd send error!\n"; + } + else + { + std::cout << "WARNING: Unsupported bshift. FPGA sample bits shift left set to 0.\n"; + if (pps_rx->send_cmd("bshift=0\n") == false) std::cout << "cmd send error!\n"; + } + + if (spattern_ == true) + { + std::cout << "FPGA debug sample pattern is active!.\n"; + if (pps_rx->send_cmd("spattern=1\n") == false) std::cout << "cmd send error!\n"; + } + else + { + std::cout << "FPGA debug sample pattern disabled.\n"; + if (pps_rx->send_cmd("spattern=0\n") == false) std::cout << "cmd send error!\n"; + } + } + else + { + std::cout << "PPS mode NOT enabled, not configuring PlutoSDR custom timestamping FPGA IP.\n"; + } + } + else + { + std::cerr << "ad936x_iio_source IIO initialization error." << std::endl; + exit(1); + } + } + else + { + std::cerr << "ad936x_iio_source IIO initialization error." << std::endl; + exit(1); + } + } + catch (std::exception const &ex) + { + std::cerr << "STD exception: " << ex.what() << std::endl; + exit(1); + } + catch (...) + { + std::cerr << "Unexpected catch" << std::endl; + exit(1); + } + + //set_min_noutput_items(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2); + set_min_output_buffer(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2); + //std::cout << "max_output_buffer " << min_output_buffer(0) << " min_noutput_items: " << min_noutput_items() << "\n"; +} ad936x_iio_source::~ad936x_iio_source() { + // Terminate PPS thread + if (pps_rx_thread.joinable()) + { + pthread_t id = pps_rx_thread.native_handle(); + pps_rx_thread.detach(); + pthread_cancel(id); + } } +bool ad936x_iio_source::start() +{ + return ad936x_custom->start_sample_rx(false); +} + +bool ad936x_iio_source::stop() +{ + ad936x_custom->stop_record(); + return true; +} + int ad936x_iio_source::general_work(int noutput_items, __attribute__((unused)) gr_vector_int &ninput_items, __attribute__((unused)) gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - std::vector out; - for (auto &output_item : output_items) + std::shared_ptr current_buffer; + ad936x_iio_samples *current_samples; + ad936x_custom->pop_sample_buffer(current_buffer); + current_samples = current_buffer.get(); + + //I and Q samples are interleaved in buffer: IQIQIQ... + + for (size_t n = 0; n < ad936x_custom->n_channels; n++) { - out.push_back(reinterpret_cast(output_item)); + if (output_items.size() > n) // check if the output channel is connected + { + memcpy(reinterpret_cast(output_items[n]), reinterpret_cast(current_samples->buffer[n]), current_samples->n_bytes[n]); + produce(n, current_samples->n_samples[n]); + } } - std::cout << "Warning!!\n"; - return 0; + + ad936x_custom->push_sample_buffer(current_buffer); + return this->WORK_CALLED_PRODUCE; } diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h index aec4a3c56..497146277 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h @@ -1,8 +1,7 @@ /*! * \file ad936x_iio_source.h - * - * \brief signal source to receive samples from the AD936x FE family over libiio, including special custom functionalities in FPGA firmware. - * \author Javier Arribas jarribas (at) cttc.es + * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- * @@ -15,19 +14,22 @@ * ----------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_AD9361_IIO_SOURCE_H -#define GNSS_SDR_AD9361_IIO_SOURCE_H +#ifndef GNSS_SDR_AD936X_IIO_SOURCE_H +#define GNSS_SDR_AD936X_IIO_SOURCE_H + +#include "ad936x_iio_custom.h" #include "concurrent_queue.h" #include "gnss_block_interface.h" +#include "ppstcprx.h" #include -#include #include -#include //multichip sync and high level functions #include #include #include +#include #include +#include #include /** \addtogroup Signal_Source @@ -41,17 +43,27 @@ class ad936x_iio_source; using ad936x_iio_source_sptr = gnss_shared_ptr; ad936x_iio_source_sptr ad936x_iio_make_source_sptr( - Concurrent_Queue *queue, - std::string pluto_device_uri, - std::string board_type, + std::string pluto_uri_, + std::string board_type_, long long bandwidth_, long long sample_rate_, - std::vector ch_list, - std::vector ch_gain_mode, - std::vector ch_gain_db, - std::vector ch_freq_hz, - int ch_sample_size, - int ch_sample_bits_shift); + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch, + bool ppsmode_, + bool customsamplesize_, + std::string fe_ip_, + int fe_ctlport_, + int ssize_, + int bshift_, + bool spattern_); /*! * \brief This class implements conversion between Labsat 2, 3 and 3 Wideband @@ -62,6 +74,11 @@ class ad936x_iio_source : public gr::block public: ~ad936x_iio_source(); + //! start the sample transmission + bool start(); + //! stop the sample transmission + bool stop(); + int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, @@ -69,32 +86,60 @@ public: private: friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr( - Concurrent_Queue *queue, - std::string pluto_device_uri, - std::string board_type, + std::string pluto_uri_, + std::string board_type_, long long bandwidth_, long long sample_rate_, - std::vector ch_list, - std::vector ch_gain_mode, - std::vector ch_gain_db, - std::vector ch_freq_hz, - int ch_sample_size, - int ch_sample_bits_shift); + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch, + bool ppsmode_, + bool customsamplesize_, + std::string fe_ip_, + int fe_ctlport_, + int ssize_, + int bshift_, + bool spattern_); - ad936x_iio_source(Concurrent_Queue *queue, - std::string pluto_device_uri, - std::string board_type, + ad936x_iio_source( + std::string pluto_uri_, + std::string board_type_, long long bandwidth_, long long sample_rate_, - std::vector ch_list, - std::vector ch_gain_mode, - std::vector ch_gain_db, - std::vector ch_freq_hz, - int ch_sample_size, - int ch_sample_bits_shift); + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch, + bool ppsmode_, + bool customsamplesize_, + std::string fe_ip_, + int fe_ctlport_, + int ssize_, + int bshift_, + bool spattern_); + + std::thread pps_rx_thread; + + + std::unique_ptr ad936x_custom; + std::shared_ptr pps_rx; + std::shared_ptr> ppsqueue; }; /** \} */ /** \} */ -#endif // GNSS_SDR_AD9361_IIO_SOURCE_H +#endif // GNSS_SDR_AD936X_IIO_SOURCE_H diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 34cb13e88..00555c424 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -8,8 +8,8 @@ set(OPT_SIGNAL_SOURCE_LIB_SOURCES "") set(OPT_SIGNAL_SOURCE_LIB_HEADERS "") if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) - set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ad9361_manager.h) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) endif() if(ENABLE_FPGA OR ENABLE_AD9361) @@ -23,6 +23,18 @@ if(ENABLE_FPGA OR ENABLE_AD9361) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma.h) endif() + +if(ENABLE_PLUTOSDR) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.h) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} pps_samplestamp.h) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h) +endif() + + set(SIGNAL_SOURCE_LIB_SOURCES rtl_tcp_commands.cc rtl_tcp_dongle_info.cc @@ -88,7 +100,7 @@ if(GNURADIO_USES_SPDLOG) ) endif() -if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) +if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR) target_link_libraries(signal_source_libs PUBLIC Iio::iio diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc new file mode 100644 index 000000000..0076c27fc --- /dev/null +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -0,0 +1,1195 @@ +/*! + * \file ad936x_iio_custom.cc + * \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ +#include "ad936x_iio_custom.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_) +{ + receive_samples = false; + fpga_overflow = false; + sample_rate_sps = 0; + ctx = NULL; + phy = NULL; + dds_dev = NULL; + stream_dev = NULL; + debug_level = debug_level_; + log_level = log_level_; + PPS_mode = false; + n_channels = 0; +} + +ad936x_iio_custom::~ad936x_iio_custom() +{ + //disable TX + if (phy != NULL) PlutoTxEnable(false); + + //Close device + if (ctx != NULL) iio_context_destroy(ctx); +} + + +void ad936x_iio_custom::set_gnsstime_queue(std::shared_ptr> queue) +{ + GnssTime_queue = std::move(queue); +} + +void ad936x_iio_custom::set_pps_samplestamp_queue(std::shared_ptr> queue) +{ + Pps_queue = std::move(queue); +} + +bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::string board_type) +{ + //Find devices + if (pluto_device_uri == "local") + { + struct iio_scan_context *tmp_ctx = iio_create_scan_context("usb", 0); + if (!tmp_ctx) + { + std::cout << "Unable to create scan context\n"; + return false; + } + + struct iio_context_info **info; + int ret = iio_scan_context_get_info_list(tmp_ctx, &info); + if (ret < 0) + { + iio_scan_context_destroy(tmp_ctx); + + std::cout << "Unable to scan for Pluto devices\n"; + return false; + } + + if (ret == 0) + { + iio_context_info_list_free(info); + iio_scan_context_destroy(tmp_ctx); + std::cout << " No Pluto device found\n "; + return false; + } + + if (ret > 1) + { + std::cout << "More than one Pluto found:\n"; + + for (unsigned int i = 0; i < (size_t)ret; i++) + { + printf("\t%d: %s [%s]\n", i, + iio_context_info_get_description(info[i]), + iio_context_info_get_uri(info[i])); + } + + std::cout << "We will use the first one.\n"; + } + + std::string uri(iio_context_info_get_uri(info[0])); + iio_context_info_list_free(info); + iio_scan_context_destroy(tmp_ctx); + + ctx = iio_create_context_from_uri(uri.c_str()); + } + else + { + ctx = iio_create_context_from_uri(pluto_device_uri.c_str()); + } + + if (ctx == NULL) + { + std::cout << "Unable to create context from uri: " << pluto_device_uri << std::endl; + return false; + } + + + phy = iio_context_find_device(ctx, "ad9361-phy"); + + if (phy == NULL) + { + std::cout << "Unable to find ad9361-phy device from uri: " << pluto_device_uri << std::endl; + return false; + } + + if (board_type.compare("fmcomms5") == 0) + { + stream_dev = iio_context_find_device(ctx, "cf-ad9361-A"); //first ad9361 in FMCOMMS5 + if (stream_dev == NULL) + { + std::cout << "Unable to find cf-ad9361-A device from uri: " << pluto_device_uri << std::endl; + return false; + }; + } + else + { + stream_dev = iio_context_find_device(ctx, "cf-ad9361-lpc"); //regular AD9361 stream device in single AD9361 boards + if (stream_dev == NULL) + { + std::cout << "Unable to find cf-ad9361-lpc device from uri: " << pluto_device_uri << std::endl; + return false; + }; + dds_dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); //DDS core for LO oscillator (external transverter operation) + if (stream_dev == NULL) + { + std::cout << "Warning: Unable to find cf-ad9361-dds-core-lpc device from uri: " << pluto_device_uri << std::endl; + }; + } + + return true; +} + + +void ad936x_iio_custom::configure_params(struct iio_device *phy, + const std::vector ¶ms) +{ + for (std::vector::const_iterator it = params.begin(); + it != params.end(); ++it) + { + struct iio_channel *chn = NULL; + const char *attr = NULL; + size_t pos; + int ret; + + pos = it->find('='); + if (pos == std::string::npos) + { + std::cerr << "Misformed line: " << *it << std::endl; + continue; + } + + std::string key = it->substr(0, pos); + std::string val = it->substr(pos + 1, std::string::npos); + + ret = iio_device_identify_filename(phy, + key.c_str(), &chn, &attr); + if (ret) + { + std::cerr << "Parameter not recognized: " + << key << std::endl; + continue; + } + + if (chn) + ret = iio_channel_attr_write(chn, + attr, val.c_str()); + else if (iio_device_find_attr(phy, attr)) + ret = iio_device_attr_write(phy, attr, val.c_str()); + else + ret = iio_device_debug_attr_write(phy, + attr, val.c_str()); + if (ret < 0) + { + std::cerr << "Unable to write attribute " << key + << ": " << ret << std::endl; + } + } +} + + +void ad936x_iio_custom::set_params_rx(struct iio_device *phy_device, + unsigned long long frequency, + unsigned long samplerate, unsigned long bandwidth, + bool quadrature, bool rfdc, bool bbdc, + std::string gain1, double gain1_value, + std::string gain2, double gain2_value, + std::string port_select) +{ + std::vector params; + + params.push_back("out_altvoltage0_RX_LO_frequency=" + + std::to_string(frequency)); + std::cout << params.back() << "\n"; + params.push_back("in_voltage_sampling_frequency=" + + std::to_string(samplerate)); + std::cout << params.back() << "\n"; + params.push_back("in_voltage_rf_bandwidth=" + + std::to_string(bandwidth)); + std::cout << params.back() << "\n"; + params.push_back("in_voltage_quadrature_tracking_en=" + + std::to_string(quadrature)); + params.push_back("in_voltage_rf_dc_offset_tracking_en=" + + std::to_string(rfdc)); + params.push_back("in_voltage_bb_dc_offset_tracking_en=" + + std::to_string(bbdc)); + params.push_back("in_voltage0_gain_control_mode=" + + gain1); + params.push_back("in_voltage0_hardwaregain=" + + std::to_string(gain1_value)); + params.push_back("in_voltage1_gain_control_mode=" + + gain2); + params.push_back("in_voltage1_hardwaregain=" + + std::to_string(gain2_value)); + params.push_back("in_voltage0_rf_port_select=" + + port_select); + + configure_params(phy_device, params); +} + + +bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_, + double phase_dds_deg_) +{ + // TX stream config + std::cout << "Start of AD9361 TX Oscillator DDS configuration\n"; + + std::cout << "* Configuring AD9361 for streaming TX\n"; + + // ENABLE DDS on TX1 + // Configure LO channel + std::vector params_phy; + + params_phy.push_back("out_altvoltage1_TX_LO_frequency=" + + std::to_string(freq_rf_tx_hz_)); + + params_phy.push_back("out_voltage0_hardwaregain=" + + std::to_string(-tx_attenuation_db_)); + + //disable the other TX + params_phy.push_back("out_voltage1_hardwaregain=" + + std::to_string(-tx_attenuation_db_)); + + + configure_params(phy, params_phy); + + std::vector params_dds; + + //DDS TX CH1 I (tone #1) + params_dds.push_back("out_altvoltage0_TX1_I_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_raw=1"); + //DDS TX CH1 Q (tone #1) + params_dds.push_back("out_altvoltage2_TX1_Q_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_raw=1"); + + //DDS TX CH1 I (tone #1) + // params_dds.push_back("out_altvoltage4_TX2_I_F1_frequency=" + + // std::to_string(freq_dds_tx_hz_)); + // params_dds.push_back("out_altvoltage4_TX2_I_F1_phase=" + + // std::to_string(phase_dds_deg_ * 1000.0)); + // params_dds.push_back("out_altvoltage4_TX2_I_F1_scale=" + + // std::to_string(scale_dds_)); + // params_dds.push_back("out_altvoltage4_TX2_I_F1_raw=1"); + // //DDS TX CH1 Q (tone #1) + // params_dds.push_back("out_altvoltage6_TX2_Q_F1_frequency=" + + // std::to_string(freq_dds_tx_hz_)); + // params_dds.push_back("out_altvoltage6_TX2_Q_F1_phase=" + + // std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); + // params_dds.push_back("out_altvoltage6_TX2_Q_F1_scale=" + + // std::to_string(scale_dds_)); + // params_dds.push_back("out_altvoltage6_TX2_Q_F1_raw=1"); + + configure_params(dds_dev, params_dds); + + return true; +} + + +bool ad936x_iio_custom::check_device() +{ + if (stream_dev != NULL) + { + return true; + } + else + { + return false; + } +} + +bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string ¶m, std::string &value) +{ + struct iio_channel *chn = 0; + const char *attr = 0; + char valuestr[256]; + int ret; + ssize_t nchars; + + ret = iio_device_identify_filename(dev, param.c_str(), &chn, &attr); + + if (ret) + { + std::cerr << "DevicePlutoSDR::get_param: Parameter not recognized: " << param << std::endl; + return false; + } + + if (chn) + { + nchars = iio_channel_attr_read(chn, attr, valuestr, 256); + } + else if (iio_device_find_attr(dev, attr)) + { + nchars = iio_device_attr_read(dev, attr, valuestr, 256); + } + else + { + nchars = iio_device_debug_attr_read(dev, attr, valuestr, 256); + } + + if (nchars < 0) + { + std::cerr << "DevicePlutoSDR::get_param: Unable to read attribute " << param << ": " << nchars << std::endl; + return false; + } + else + { + value.assign(valuestr); + return true; + } +} + +bool ad936x_iio_custom::read_die_temp(double &temp_c) +{ + std::string temp_mC_str; + + if (get_iio_param(phy, "in_temp0_input", temp_mC_str)) + { + try + { + uint32_t temp_mC = boost::lexical_cast(temp_mC_str); + temp_c = static_cast(temp_mC) / 1000.0; + if (temp_c > 120) temp_c = -1; + return true; + } + catch (const boost::bad_lexical_cast &e) + { + std::cerr << "PlutoSDRDevice::getTemp: bad conversion to numeric" << std::endl; + return false; + } + } + else + { + return false; + } +} +bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, + long long sample_rate_, + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch) + +{ + if (check_device() == false) return false; + + bool no_errors = true; + std::cout << "Configuring phy device parameters...\n"; + int ret; + if (rf_filter.compare("Disabled") == 0) + { + std::cout << "LNA Filter switch is disabled.\n"; + } + else if (rf_filter.compare("Auto") == 0) + { + std::cout << "Selecting LNA RF filter based on the selected RF frequency... \n"; + if (freq_ == 1575420000) + { + if (select_rf_filter("E1") == true) + { + std::cout << "LNA RF filter board switch set to E1\n"; + } + else + { + std::cout << "Problem setting LNA RF filter switch value\n"; + } + } + else + { + if (select_rf_filter("E5E6") == true) + { + std::cout << "LNA RF filter board switch set to E5E6\n"; + } + else + { + std::cout << "Problem setting LNA RF filter switch value\n"; + } + } + } + else + { + if (select_rf_filter(rf_filter) == true) + { + std::cout << "LNA RF filter board switch set to " << rf_filter << "\n"; + } + else + { + std::cout << "Problem setting LNA RF filter switch value\n"; + } + } + + std::vector params; + // Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator) + params.push_back("out_altvoltage0_RX_LO_frequency=" + + std::to_string(freq_)); + + sample_rate_sps = sample_rate_; + + params.push_back("in_voltage_sampling_frequency=" + + std::to_string(sample_rate_)); + + params.push_back("out_voltage_sampling_frequency=" + + std::to_string(sample_rate_)); + + params.push_back("in_voltage_rf_bandwidth=" + + std::to_string(bandwidth_)); + + params.push_back("out_voltage_rf_bandwidth=" + + std::to_string(bandwidth_)); + + params.push_back("in_voltage_quadrature_tracking_en=1"); + params.push_back("in_voltage_rf_dc_offset_tracking_en=1"); + params.push_back("in_voltage_bb_dc_offset_tracking_en=1"); + + configure_params(phy, params); + + ret = iio_device_attr_write(phy, "trx_rate_governor", "nominal"); + if (ret < 0) + { + std::cerr << "Failed to set trx_rate_governor: " << ret << std::endl; + no_errors = false; + } + ret = iio_device_attr_write(phy, "ensm_mode", "fdd"); + if (ret < 0) + { + std::cerr << "Failed to set ensm_mode: " << ret << std::endl; + no_errors = false; + } + ret = iio_device_attr_write(phy, "calib_mode", "auto"); + if (ret < 0) + { + std::cerr << "Failed to set calib_mode: " << ret << std::endl; + no_errors = false; + } + + + std::cout << "no_errors: " << no_errors << "\n"; + + if (enable_ch1 == true and enable_ch0 == true and freq_ != freq_2ch) + { + std::cout << "Two channels enabled with different frequencies, enabling the external RF transverter board:\n"; + long long int delta_freq_hz = freq_2ch - freq_; + if (delta_freq_hz < 0) + { + std::cout << "Configuration problem: 2nd channel frequency is " << freq_2ch << " [Hz], must be higher than main channel (" << freq_ << " [Hz])\n"; + return false; + } + + std::cout << "Configuring DDS Local Oscillator generation. LO Freq. is " << delta_freq_hz << " [Hz]\n"; + PlutoTxEnable(true); + config_ad9361_dds(delta_freq_hz, + 30, + 100000, + 0.9, + 0); + std::cout << "Configuring DDS Local Oscillator generation DONE\n"; + } + else + { + PlutoTxEnable(false); //power down the TX LO to reduce interferences + } + + if (enable_ch0 == true) + { + n_channels++; + std::cerr << "* Get AD9361 Phy RX channel 0...\n"; + std::stringstream name; + name.str(""); + name << "voltage"; + name << 0; + struct iio_channel *phy_ch; + phy_ch = iio_device_find_channel(phy, name.str().c_str(), false); //false means RX + if (!phy_ch) + { + std::cerr << "Could not find AD9361 phy channel: " << name.str() << "\n"; + no_errors = false; + } + + ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); + if (ret < 0) + { + std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; + no_errors = false; + } + + ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + if (ret < 0) + { + std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + no_errors = false; + } + + long long set_rf_bw; + ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); + if (ret < 0) + { + std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; + no_errors = false; + } + else + { + std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; + } + + + if (setRXGain(0, gain_mode_rx0_, rf_gain_rx0_) == false) + { + std::cerr << "Info: setRXGain read returned false \n"; + no_errors = false; + } + } + + if (enable_ch1 == true) + { + n_channels++; + std::cerr << "* Get AD9361 Phy RX channel 1...\n"; + std::stringstream name; + name.str(""); + name << "voltage"; + name << 1; + struct iio_channel *phy_ch; + phy_ch = iio_device_find_channel(phy, name.str().c_str(), false); //false means RX + if (!phy_ch) + { + std::cerr << "Could not find AD9361 phy channel: " << name.str() << "\n"; + no_errors = false; + } + + ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); + if (ret < 0) + { + std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; + no_errors = false; + } + + ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + if (ret < 0) + { + std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + no_errors = false; + } + + if (setRXGain(1, gain_mode_rx1_, rf_gain_rx1_) == false) + { + std::cerr << "Info: setRXGain read returned false \n"; + no_errors = false; + } + } + + int set_filter_ret = ad9361_set_bb_rate_custom_filter_auto(phy, sample_rate_sps); + if (set_filter_ret != 0) + { + std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + } + + //testing: set manual RX filter chain + // unsigned long RX_analog_bb_lpf_stop_hz = 1000000; + // unsigned long TX_analog_bb_lpf_stop_hz = 1000000; + // + // unsigned long FIR_lpf_passband_hz = 1000000; + // unsigned long FIR_lpf_stopband_hz = 1200000; + // int set_filter_ret = ad9361_set_bb_rate_custom_filter_manual(phy, + // sample_rate_sps, + // FIR_lpf_passband_hz, + // FIR_lpf_stopband_hz, + // RX_analog_bb_lpf_stop_hz, + // TX_analog_bb_lpf_stop_hz); + // if (set_filter_ret != 0) + // { + // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + // } + + std::cout << "AD936x Front-end configuration summary: \n"; + std::cout << "Baseband sampling frequency: " << sample_rate_sps << " [SPS]\n"; + std::cout << "RX chain gain: " << rf_gain_rx0_ << " [dB][only valid in manual mode]\n"; + std::cout << "RX chain gain mode: " << gain_mode_rx0_ << "\n"; + // std::cout << "Analog baseband LPF stop frequency: " << RX_analog_bb_lpf_stop_hz << " [Hz]\n"; + // std::cout << "Digital baseband LPF FIR passband frequency: " << FIR_lpf_passband_hz << " [Hz]\n"; + // std::cout << "Digital baseband LPF FIR stopband frequency: " << FIR_lpf_stopband_hz << " [Hz]\n"; + std::cout << "End of AD9361 RX configuration.\n"; + return no_errors; +} + +bool ad936x_iio_custom::set_rx_frequency(long long freq_hz) +{ + if (check_device() == false) return false; + // Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator) + struct iio_channel *lo_ch; + + lo_ch = iio_device_find_channel(phy, "altvoltage0", true); + if (!lo_ch) + { + std::cerr << "Could not find AD9361 RX LO channel altvoltage0\n"; + return false; + } + int ret; + ret = iio_channel_attr_write_longlong(lo_ch, "frequency", freq_hz); + if (ret < 0) + { + std::cerr << "Warning: RX LO frequency write returned: " << ret << "\n"; + return false; + } + return true; +} + + +bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz) +{ + if (check_device() == false) return false; + // Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator) + struct iio_channel *lo_ch; + + lo_ch = iio_device_find_channel(phy, "altvoltage0", true); + if (!lo_ch) + { + std::cerr << "Could not find AD9361 RX LO channel altvoltage0\n"; + return false; + } + int ret; + ret = iio_channel_attr_read_longlong(lo_ch, "frequency", &freq_hz); + if (ret < 0) + { + std::cerr << "Warning: RX LO frequency read returned: " << ret << "\n"; + return false; + } + return true; +} + +bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain_dB) +{ + if (check_device() == false) return false; + std::vector params; + if (ch_num == 0) + { + params.clear(); + params.push_back("in_voltage0_gain_control_mode=" + gain_mode); + if (gain_mode == "manual") + { + params.push_back("in_voltage0_hardwaregain=" + std::to_string(gain_dB)); + } + configure_params(phy, params); + return true; + } + else if (ch_num == 1) + { + params.clear(); + params.push_back("in_voltage1_gain_control_mode=" + gain_mode); + if (gain_mode == "manual") + { + params.push_back("in_voltage1_hardwaregain=" + std::to_string(gain_dB)); + } + configure_params(phy, params); + return true; + } + else + { + return false; + } +} + +double ad936x_iio_custom::get_rx_gain(int ch_num) +{ + if (check_device() == false) return -1; + double gain_dB; //gain in dB + int ret = 0; + if (ch_num == 0) + { + ret = iio_device_attr_read_double(phy, "in_voltage0_hardwaregain", &gain_dB); + if (ret < 0) + { + std::cerr << "Failed to read in_voltage0_hardwaregain: " << ret << std::endl; + return -1.0; + } + } + else if (ch_num == 1) + { + ret = iio_device_attr_read_double(phy, "in_voltage1_hardwaregain", &gain_dB); + if (ret < 0) + { + std::cerr << "Failed to read in_voltage1_hardwaregain: " << ret << std::endl; + return -1.0; + } + } + else + { + return -1.0; + } + return gain_dB; +} + + +bool ad936x_iio_custom::calibrate(int ch, double bw_hz) +{ + if (check_device() == false) return false; + //todo + return true; +} + +void ad936x_iio_custom::monitor_thread_fn() +{ + uint32_t val; + int ret; + + /* Give the main thread a moment to start the DMA */ + sleep(1); + + /* Clear all status bits */ + ret = iio_device_reg_write(stream_dev, 0x80000088, 0x6); + if (ret) + { + fprintf(stderr, "Failed to clearn DMA status register: %s\n", + strerror(-ret)); + } + + while (receive_samples) + { + ret = iio_device_reg_read(stream_dev, 0x80000088, &val); + if (ret) + { + fprintf(stderr, "Failed to read status register: %s\n", + strerror(-ret)); + continue; + } + + // if (device_is_tx) { + // if (val & 1) + // fprintf(stderr, "Underflow detected\n"); + // } else { + if (val & 4) + { + std::cout << "WARNING: IIO status register reported overflow!\n"; + LOG(INFO) << "WARNING: IIO status register reported overflow!"; + } + + + /* Clear bits */ + if (val) + { + ret = iio_device_reg_write(stream_dev, 0x80000088, val); + if (ret) + fprintf(stderr, "Failed to clearn DMA status register: %s\n", + strerror(-ret)); + } + sleep(1); + } + return; +} + +void ad936x_iio_custom::stop_record() +{ + receive_samples = false; + + if (capture_time_thread.joinable() == true) + { + std::cout << "Joining sample cature thread...\n"; + capture_samples_thread.join(); + } + + if (capture_time_thread.joinable() == true) + { + std::cout << "Joining overflow monitor thread...\n"; + overflow_monitor_thread.join(); + } + + if (capture_time_thread.joinable() == true) + { + std::cout << "Joining time cature thread...\n"; + capture_time_thread.join(); + } +} + + +void ad936x_iio_custom::PlutoTxEnable(bool txon) +{ + if (check_device()) + { + int ret; + if (txon == false) + { + ret = iio_channel_attr_write_bool(iio_device_find_channel(phy, "altvoltage1", true), "powerdown", true); //turn off TX LO + if (ret < 0) + { + std::cerr << "Failed to write altvoltage1 powerdown: " << ret << std::endl; + } + } + else + { + ret = iio_channel_attr_write_bool(iio_device_find_channel(phy, "altvoltage1", true), "powerdown", false); //turn on TX LO + if (ret < 0) + { + std::cerr << "Failed to write altvoltage1 powerdown: " << ret << std::endl; + } + } + } +} + +void ad936x_iio_custom::setPlutoGpo(int p) +{ + char pins[11]; + sprintf(pins, "0x27 0x%x0", p); //direct access to AD9361 registers... WARNING! + pins[9] = 0; + int ret; + //std::cout << "send: " << pins << " \n"; + if (check_device()) + { + ret = iio_device_debug_attr_write(phy, "direct_reg_access", pins); + if (ret < 0) + { + std::cerr << "Failed to write direct_reg_access: " << ret << std::endl; + } + } +} + + +bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) +{ + // adi,gpo-manual-mode-enable Enables GPO manual mode, this will conflict with automatic ENSM slave and eLNA mode + // adi,gpo-manual-mode-enable-mask Enable bit mask, setting or clearing bits will change the level of the corresponding output. Bit0 → GPO, Bit1 → GPO1, Bit2 → GPO2, Bit3 → GP03 + // adi,gpo-manual-mode-enable + // adi,gpo-manual-mode-enable-mask does not work... + // some software use the direct_reg_access (see https://github.com/g4eml/Langstone/blob/master/LangstoneGUI.c) + + //since plutosdr fw 31: + // GPOs can be addressed individual 0..3 or altogether using 0xF as Identifier. + // + // SYNTAX: + // + // gpo_set + // Enable + // Value Function + // 0 Disable + // 1 Enable + // X Enable Mask if Identifier=0xF + + + if (check_device() == false) return false; + int plutoGpo = 0; + int ret; + ret = iio_device_debug_attr_write(phy, "adi,gpo-manual-mode-enable", "1"); + + if (ret < 0) + { + std::cerr << "Failed to write adi,gpo-manual-mode-enable: " << ret << std::endl; + return false; + } + + if (rf_filter.compare("E1") == 0) + { + //set gpio0 to switch L1 filter + // setPlutoGpo(plutoGpo); + ret = iio_device_debug_attr_write(phy, "gpo_set", "0 0"); + if (ret < 0) + { + std::cerr << "Failed to write gpo_set: " << ret << std::endl; + return false; + } + } + else if (rf_filter.compare("E5E6") == 0) + { + //set gpio0 to switch L5/L6 filter (GPO0) + // plutoGpo = plutoGpo | 0x10; + // setPlutoGpo(plutoGpo); //set the Pluto GPO Pin + ret = iio_device_debug_attr_write(phy, "gpo_set", "0 1"); + if (ret < 0) + { + std::cerr << "Failed to write gpo_set: " << ret << std::endl; + return false; + } + } + if (rf_filter.compare("none") == 0) + { + std::cout << "RF external filter not selected\n"; + } + + else + { + std::cout << "Unknown filter selected, switching to E1 filter...\n"; + ret = iio_device_debug_attr_write(phy, "gpo_set", "0 0"); + if (ret < 0) + { + std::cerr << "Failed to write gpo_set: " << ret << std::endl; + return false; + } + } + + return true; +} +void ad936x_iio_custom::get_PPS_timestamp() +{ + GnssTime tow; + PpsSamplestamp pps; + GnssTime_queue->clear(); + Pps_queue->clear(); + + std::cout << "Waiting for uBlox time message synchronization... (wait up to 10 seconds)\n"; + if (GnssTime_queue->timed_wait_and_pop(tow, 10000) == false) + { + std::cout << "uBlox time message synchronization error.\n"; + return; + } + + std::cout << "Waiting for PPS Samplestamp message synchronization... (wait up to 10 seconds)\n"; + if (Pps_queue->timed_wait_and_pop(pps, 10000) == false) + { + std::cout << "PPS IP message synchronization error.\n"; + return; + } + + //Get new PPS samplestamp and associate it to the corresponding uBlox TP message + while (receive_samples == true) + { + std::cout << "[" << pps.samplestamp << "][o:" << pps.overflow_reg << "] uBlox time message received with TOW=" << tow.tow_ms << "\n"; + LOG(INFO) << "[" << pps.samplestamp << "][o:" << pps.overflow_reg << "] uBlox time message received with TOW=" << tow.tow_ms << "\n"; + //write timestamp information to timestamp metadata file: + //uint64_t: absolute sample counter from the beginning of sample capture associated to the rising edge of the PPS signal + // ppstimefile.write(reinterpret_cast(&pps.samplestamp), sizeof(uint64_t)); + //int32_t: Galileo/GPS Week Number associated to the rising edge of PPS signal + // ppstimefile.write(reinterpret_cast(&tow.week), sizeof(int32_t)); + //int32_t: Galileo/GPS TOW associated to the rising edge of PPS signal + // ppstimefile.write(reinterpret_cast(&tow.tow_ms), sizeof(int32_t)); + //record pps rise samplestamp associated to the absolute sample counter + //PPS rising edge must be associated with the corresponding uBlox time message (tx once a second) + + + if (GnssTime_queue->timed_wait_and_pop(tow, 2000) == false) + { + if (receive_samples == true) + { + std::cout << "ERROR: uBlox time message not received, check uBlox GNSS signal quality!\n"; + LOG(INFO) << "ERROR: uBlox time message not received!"; + } + break; + } + if (Pps_queue->timed_wait_and_pop(pps, 2000) == false) + { + if (receive_samples == true) + { + std::cout << "ERROR: PPS time message not received, check uBlox GNSS signal quality!\n"; + LOG(INFO) << "ERROR: PPS time message not received!"; + } + break; + } + if (pps.overflow_reg > 0) + { + if (receive_samples == true) + { + fpga_overflow = true; + std::cout << "ERROR: FPGA reported RX sample buffer overflow!\n"; + LOG(INFO) << "ERROR: FPGA reported RX sample buffer overflow!\n"; + } + break; + } + } +} +bool ad936x_iio_custom::start_sample_rx(bool ppsmode) +{ + //using queues of smart pointers to preallocated buffers + free_buffers.clear(); + used_buffers.clear(); + //preallocate buffers and use queues + std::cerr << "Allocating memory..\n"; + try + { + for (int n = 0; n < IIO_INPUTRAMFIFOSIZE; n++) + { + free_buffers.push(std::make_shared()); + } + } + catch (const std::exception &ex) + { + std::cout << "ERROR: Problem allocating RAM buffer: " << ex.what() << "\n"; + return false; + } + + //prepare capture channels + std::vector channels; + switch (n_channels) + { + case 1: + channels.push_back("voltage0"); //Channel 0 I + channels.push_back("voltage1"); //Channel 0 Q + break; + case 2: + channels.push_back("voltage0"); //Channel 0 I + channels.push_back("voltage1"); //Channel 0 Q + channels.push_back("voltage2"); //Channel 1 I + channels.push_back("voltage3"); //Channel 1 Q + break; + default: + channels.push_back("voltage0"); //Channel 0 I + channels.push_back("voltage1"); //Channel 0 Q + } + + receive_samples = true; + //start sample capture thread + capture_samples_thread = std::thread(&ad936x_iio_custom::capture, this, channels); + //start sample overflow detector + overflow_monitor_thread = std::thread(&ad936x_iio_custom::monitor_thread_fn, this); + + + //start PPS and GNSS Time capture thread + + if (ppsmode == true) + { + capture_time_thread = std::thread(&ad936x_iio_custom::get_PPS_timestamp, this); + } + return true; +} + +void ad936x_iio_custom::pop_sample_buffer(std::shared_ptr ¤t_buffer) +{ + used_buffers.wait_and_pop(current_buffer); +} + +void ad936x_iio_custom::push_sample_buffer(std::shared_ptr ¤t_buffer) +{ + free_buffers.push(current_buffer); +} + +void ad936x_iio_custom::capture(const std::vector &channels) +{ + if (check_device() == false) return; + + struct iio_buffer *rxbuf; + + std::vector channel_list; + + /* First disable all channels */ + unsigned int nb_channels; + nb_channels = iio_device_get_channels_count(stream_dev); + for (unsigned int i = 0; i < nb_channels; i++) + { + iio_channel_disable(iio_device_get_channel(stream_dev, i)); + } + + // enable channels + if (channels.empty()) + { + for (unsigned int i = 0; i < nb_channels; i++) + { + struct iio_channel *chn = + iio_device_get_channel(stream_dev, i); + + iio_channel_enable(chn); + channel_list.push_back(chn); + } + } + else + { + for (std::vector::const_iterator it = + channels.begin(); + it != channels.end(); ++it) + { + struct iio_channel *chn = + iio_device_find_channel(stream_dev, + it->c_str(), false); + if (!chn) + { + std::cerr << "Channel " << it->c_str() << " not found\n"; + return; + } + else + { + iio_channel_enable(chn); + channel_list.push_back(chn); + } + } + } + + const struct iio_data_format *format = iio_channel_get_data_format(channel_list[0]); + + std::cerr << "Format: length " << format->length + << " bits " << format->bits + << " shift " << format->shift + << " is_signed " << format->is_signed + << " is_fully_defined " << format->is_fully_defined + << " is_be " << format->is_be + << " with_scale " << format->with_scale + << " scale " << format->scale + << " repeat " << format->repeat << "\n"; + + rxbuf = iio_device_create_buffer(stream_dev, IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES, false); + if (!rxbuf) + { + std::cout << "Could not create RX buffer. \n"; + return; + } + + std::shared_ptr current_buffer; + ad936x_iio_samples *current_samples; + unsigned long items_in_buffer; + std::cerr << "Enter capture loop...\n"; + int ret; + int bytes_per_channel = static_cast(channels.size()) * 2; //each channel has two items in channels vector (I,Q). Each component has two bytes. + while (receive_samples == true) + { + free_buffers.wait_and_pop(current_buffer); + current_samples = current_buffer.get(); + ret = iio_buffer_refill(rxbuf); + if (ret < 0) + { + /* -EBADF happens when the buffer is cancelled */ + if (ret != -EBADF) + { + char err_buf[256]; + iio_strerror(-ret, err_buf, sizeof(err_buf)); + std::string error(err_buf); + + std::cerr << "Unable to refill buffer: " << error << std::endl; + iio_buffer_destroy(rxbuf); + return; + } + } + + // Demultiplex the samples of a given channel + int n_ch = 0; + for (auto it = std::begin(channel_list); it != std::end(channel_list); ++it) + { + current_samples->n_bytes[n_ch] = iio_channel_read_raw(*it, rxbuf, ¤t_samples->buffer[n_ch][0], IIO_MAX_BYTES_PER_CHANNEL); + current_samples->n_samples[n_ch] = current_samples->n_bytes[n_ch] / sizeof(short); + n_ch++; + } + + // old, valid only for one channel + //memcpy(¤t_samples->buffer[0], iio_buffer_start(rxbuf), ret); + + if (current_samples->n_bytes[0] == 0) return; + + used_buffers.push(current_buffer); + } + + iio_buffer_destroy(rxbuf); +} diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.h b/src/algorithms/signal_source/libs/ad936x_iio_custom.h new file mode 100644 index 000000000..f8c1fe718 --- /dev/null +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.h @@ -0,0 +1,144 @@ +/*! + * \file ad936x_iio_custom.h + * \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities. + * \author Javier Arribas, jarribas(at)cttc.es + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef SRC_LIBS_ad936x_iio_custom_H_ +#define SRC_LIBS_ad936x_iio_custom_H_ + +#include "concurrent_queue.h" +#include "gnss_time.h" +#include "pps_samplestamp.h" +#include +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "ad936x_iio_samples.h" +#include //multichip sync and high level functions +#include +#include + +class ad936x_iio_custom +{ +public: + ad936x_iio_custom(int debug_level_, int log_level_); + virtual ~ad936x_iio_custom(); + bool initialize_device(std::string pluto_device_uri, std::string board_type); + + bool init_config_ad9361_rx(long long bandwidth_, + long long sample_rate_, + long long freq_, + std::string rf_port_select_, + std::string rf_filter, + std::string gain_mode_rx0_, + std::string gain_mode_rx1_, + double rf_gain_rx0_, + double rf_gain_rx1_, + bool enable_ch0, + bool enable_ch1, + long long freq_2ch); + + bool calibrate(int ch, double bw_hz); + + double get_rx_gain(int ch_num); + bool setRXGain(int ch_num, std::string gain_mode, double gain_dB); + + bool set_antenna_port(int ch, int antenna_idx); + double get_frequency(int ch); + bool set_frequency(int ch, double freq_hz); + + bool start_sample_rx(bool ppsmode); + void stop_record(); + + void set_gnsstime_queue(std::shared_ptr> queue); + void set_pps_samplestamp_queue(std::shared_ptr> queue); + + bool get_rx_frequency(long long &freq_hz); + bool set_rx_frequency(long long freq_hz); + bool read_die_temp(double &temp_c); + + void pop_sample_buffer(std::shared_ptr ¤t_buffer); + + void push_sample_buffer(std::shared_ptr ¤t_buffer); + + int n_channels; + +private: + std::shared_ptr> GnssTime_queue; + std::shared_ptr> Pps_queue; + bool check_device(); + bool get_iio_param(iio_device *dev, const std::string ¶m, std::string &value); + void configure_params(struct iio_device *phy, + const std::vector ¶ms); + void set_params_rx(struct iio_device *phy_device, + unsigned long long frequency, + unsigned long samplerate, unsigned long bandwidth, + bool quadrature, bool rfdc, bool bbdc, + std::string gain1, double gain1_value, + std::string gain2, double gain2_value, + std::string port_select); + + bool config_ad9361_dds(uint64_t freq_rf_tx_hz_, + double tx_attenuation_db_, + int64_t freq_dds_tx_hz_, + double scale_dds_, + double phase_dds_deg_); + + void get_PPS_timestamp(); + void capture(const std::vector &channels); + + bool select_rf_filter(std::string rf_filter); + + void monitor_thread_fn(); + + void PlutoTxEnable(bool txon); + void setPlutoGpo(int p); + + //Device structure + struct iio_context *ctx; + struct iio_device *phy; + struct iio_device *stream_dev; + struct iio_device *dds_dev; + + //stream + + uint64_t sample_rate_sps; + + + int debug_level; + int log_level; + bool PPS_mode; + + std::mutex mtx; + std::condition_variable cv; + + boost::atomic receive_samples; + + boost::atomic fpga_overflow; + //using queues of smart pointers to preallocated buffers + Concurrent_Queue> free_buffers; + Concurrent_Queue> used_buffers; + + std::thread capture_samples_thread; + std::thread overflow_monitor_thread; + std::thread capture_time_thread; +}; + +#endif /* SRC_LIBS_ad936x_iio_custom_H_ */ diff --git a/src/algorithms/signal_source/libs/ad936x_iio_samples.cc b/src/algorithms/signal_source/libs/ad936x_iio_samples.cc new file mode 100644 index 000000000..7d1ef5681 --- /dev/null +++ b/src/algorithms/signal_source/libs/ad936x_iio_samples.cc @@ -0,0 +1,26 @@ +/*! + * \file ad936x_iio_samples.cc + * \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "ad936x_iio_samples.h" + +ad936x_iio_samples::ad936x_iio_samples() +{ + for (int n = 0; n < IIO_MAX_CH; n++) + { + n_bytes[n] = 0; + n_samples[n] = 0; + } +} diff --git a/src/algorithms/signal_source/libs/ad936x_iio_samples.h b/src/algorithms/signal_source/libs/ad936x_iio_samples.h new file mode 100644 index 000000000..5e932075c --- /dev/null +++ b/src/algorithms/signal_source/libs/ad936x_iio_samples.h @@ -0,0 +1,41 @@ +/*! + * \file ad936x_iio_samples.h + * \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef SRC_LIBS_ad936x_iio_samples_H_ +#define SRC_LIBS_ad936x_iio_samples_H_ + +#define IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES 32768 * 2 + +#define IIO_INPUTRAMFIFOSIZE 512 + +#define IIO_MAX_CH 4 +#define IIO_MAX_BYTES_PER_CHANNEL IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2 * 2 //(2-bytes per I + 2-bytes per Q) + +#include +#include +#include + +class ad936x_iio_samples +{ +public: + ad936x_iio_samples(); + uint32_t n_bytes[IIO_MAX_CH]; + uint32_t n_samples[IIO_MAX_CH]; + int16_t buffer[IIO_MAX_CH][IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2]; //16 bits I,Q samples buffers +}; + +#endif diff --git a/src/algorithms/signal_source/libs/pps_samplestamp.h b/src/algorithms/signal_source/libs/pps_samplestamp.h new file mode 100644 index 000000000..cdbc1276f --- /dev/null +++ b/src/algorithms/signal_source/libs/pps_samplestamp.h @@ -0,0 +1,20 @@ +/* ------------------------------------------------------------------------- + * + * Copyright (C) 2022 (see AUTHORS file for a list of contributors) + * + * + */ + +#ifndef IIOPPS_PPS_SAMPLESTAMP_H +#define IIOPPS_PPS_SAMPLESTAMP_H + +#include + +class PpsSamplestamp +{ +public: + uint64_t samplestamp; //PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side + uint32_t overflow_reg; // >0 indicates overflow situation in the FPGA RX buffer +}; + +#endif diff --git a/src/algorithms/signal_source/libs/ppstcprx.cc b/src/algorithms/signal_source/libs/ppstcprx.cc new file mode 100644 index 000000000..0a10d8545 --- /dev/null +++ b/src/algorithms/signal_source/libs/ppstcprx.cc @@ -0,0 +1,154 @@ +/* + * ppstcprx.cc + * + * Created on: 28 feb 2022 + * Author: javier + */ + +#include "ppstcprx.h" +#include +#include +#include +#include + +pps_tcp_rx::pps_tcp_rx() +{ + // TODO Auto-generated constructor stub + is_connected = false; + clientSd = -1; +} + +pps_tcp_rx::~pps_tcp_rx() +{ + // TODO Auto-generated destructor stub +} + +void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr> queue) +{ + Pps_queue = std::move(queue); +} + +bool pps_tcp_rx::send_cmd(std::string cmd) +{ + if (is_connected == true) + { + // send call sends the data you specify as second param and it's length as 3rd param, also returns how many bytes were actually sent + auto bytes_sent = send(clientSd, cmd.data(), cmd.length(), 0); + if (bytes_sent <= 0) + { + std::cerr << "Connection terminated...\n"; + return false; + } + else + { + std::cout << "sent bytes..\n"; + } + } + else + { + return false; + } + return true; +} +void pps_tcp_rx::receive_pps(std::string ip_address, int port) +{ + //create a message buffer + char buf[1500]; + //setup a socket and connection tools + sockaddr_in sendSockAddr; + sendSockAddr.sin_family = AF_INET; + sendSockAddr.sin_addr.s_addr = + inet_addr(ip_address.c_str()); + sendSockAddr.sin_port = htons(port); + clientSd = socket(AF_INET, SOCK_STREAM, 0); + //try to connect... + int status = connect(clientSd, + (sockaddr *)&sendSockAddr, sizeof(sendSockAddr)); + if (status < 0) + { + std::cout << "pps_tcp_rx: Error connecting to PPS TCP server IP " << ip_address << " at port " << port << std::endl; + return; + } + std::string new_pps_line; + + is_connected = true; + while (true) + { + int numBytesRead = recv(clientSd, buf, sizeof(buf), 0); + if (numBytesRead > 0) + { + for (int i = 0; i < numBytesRead; i++) + { + char c = buf[i]; + if (c == '\n') + { + if (new_pps_line.length() > 0) + { + //std::cout << "pps_tcp_rx debug: " << new_pps_line << "\n"; + //parse string and push PPS data to the PPS queue + std::stringstream ss(new_pps_line); + std::vector data; + while (ss.good()) + { + std::string substr; + std::getline(ss, substr, ','); + data.push_back(substr); + } + if (data.size() >= 2) + { + PpsSamplestamp new_pps; + //sample counter + std::size_t found = data.at(0).find("sc="); + if (found != std::string::npos) + { + try + { + new_pps.samplestamp = std::strtoul(data.at(0).substr(found + 3).c_str(), NULL, 0); + } + catch (const std::exception &ex) + { + std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n"; + } + } + else + { + std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n"; + } + found = data.at(1).find("o="); + if (found != std::string::npos) + { + try + { + new_pps.overflow_reg = std::stoi(data.at(1).substr(found + 2).c_str(), NULL, 0); + } + catch (const std::exception &ex) + { + std::cout << "pps_tcp_rx debug: o parse error str " << data.at(0) << "\n"; + } + } + else + { + std::cout << "pps_tcp_rx debug: o parse error str " << data.at(1) << "\n"; + } + Pps_queue->push(new_pps); + //std::cout << "pps_tcp_rx debug: pps pushed!\n"; + } + else + { + std::cout << "pps_tcp_rx debug: protocol error!\n"; + } + new_pps_line = ""; + } + } + else + new_pps_line += c; + } + } + else + { + std::cout << "pps_tcp_rx: Socket disconnected!\n!"; + break; + } + } + is_connected = false; +} diff --git a/src/algorithms/signal_source/libs/ppstcprx.h b/src/algorithms/signal_source/libs/ppstcprx.h new file mode 100644 index 000000000..37c8de92f --- /dev/null +++ b/src/algorithms/signal_source/libs/ppstcprx.h @@ -0,0 +1,34 @@ +/* + * ppstcprx.h + * + * Created on: 28 feb 2022 + * Author: javier + */ + +#ifndef SRC_LIBS_PPSTCPRX_H_ +#define SRC_LIBS_PPSTCPRX_H_ +#include "concurrent_queue.h" +#include "pps_samplestamp.h" +#include +#include +#include +#include +#include +class pps_tcp_rx +{ +private: + std::shared_ptr> Pps_queue; + int clientSd; + +public: + volatile bool is_connected; + pps_tcp_rx(); + virtual ~pps_tcp_rx(); + + void receive_pps(std::string ip_address, int port); + bool send_cmd(std::string cmd); + + void set_pps_samplestamp_queue(std::shared_ptr> queue); +}; + +#endif /* SRC_LIBS_PPSTCPRX_H_ */ diff --git a/src/core/receiver/concurrent_queue.h b/src/core/receiver/concurrent_queue.h index fc5c97053..ac7be0f17 100644 --- a/src/core/receiver/concurrent_queue.h +++ b/src/core/receiver/concurrent_queue.h @@ -55,6 +55,18 @@ public: return the_queue.empty(); } + size_t size() const + { + std::unique_lock lock(the_mutex); + return the_queue.size(); + } + + void clear() + { + std::unique_lock lock(the_mutex); + the_queue = std::queue(); + } + bool try_pop(Data& popped_value) { std::unique_lock lock(the_mutex); diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index adba9c0df..d7bd03b97 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -153,6 +153,7 @@ #endif #if PLUTOSDR_DRIVER +#include "ad936x_custom_signal_source.h" #include "plutosdr_signal_source.h" #endif @@ -775,6 +776,12 @@ std::unique_ptr GNSSBlockFactory::GetBlock( out_streams, queue); block = std::move(block_); } + else if (implementation == "Ad936x_Custom_Signal_Source") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } #endif #if FMCOMMS2_DRIVER From 0c5d38145f21beecc1938df95f1e41239ca596c0 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 30 Aug 2022 15:28:18 +0200 Subject: [PATCH 17/31] Adding extra control for the AD936x custom source external mixer --- .../adapters/ad936x_custom_signal_source.cc | 55 ++++++--- .../adapters/ad936x_custom_signal_source.h | 10 +- .../gnuradio_blocks/ad936x_iio_source.cc | 20 +++- .../gnuradio_blocks/ad936x_iio_source.h | 12 +- .../signal_source/libs/ad936x_iio_custom.cc | 108 +++++++++++------- .../signal_source/libs/ad936x_iio_custom.h | 4 +- 6 files changed, 138 insertions(+), 71 deletions(-) diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc index a999d1025..5229405dd 100644 --- a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc @@ -56,12 +56,13 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* PPS_mode_(configuration->property(role + ".PPS_mode", false)), fe_ip_(configuration->property(role + ".fe_ip", std::string("192.168.2.1"))), fe_ctlport_(configuration->property(role + ".fe_ctlport", int32_t(10000))), - ssize_(configuration->property(role + ".ssize", int32_t(16))), + ssize_(configuration->property(role + ".ssize", int32_t(12))), bshift_(configuration->property(role + ".bshift", int64_t(0))), spattern_(configuration->property(role + ".spattern", false)), inverted_spectrum_ch0_(configuration->property(role + ".inverted_spectrum_ch0", false)), - inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false)) - + inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false)), + lo_attenuation_db_(configuration->property(role + ".lo_attenuation_db", 6.0)), + high_side_lo_(configuration->property(role + ".high_side_lo", false)) { if (item_type_ == "gr_complex") @@ -69,7 +70,11 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* item_size_ = sizeof(gr_complex); // 1. Make the driver instance bool customsamplesize = false; - if (ssize_ != 16 or spattern_ == true) customsamplesize = true; + if (ssize_ != 12 or spattern_ == true) customsamplesize = true; // custom FPGA DMA firmware + if (ssize_ == 12) // default original FPGA DMA firmware + { + ssize_ = 16; // set to 16 bits and do not try to change sample size + } ad936x_iio_source = ad936x_iio_make_source_sptr( pluto_uri_, @@ -92,7 +97,9 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* fe_ctlport_, ssize_, bshift_, - spattern_); + spattern_, + lo_attenuation_db_, + high_side_lo_); n_channels = 1; if (enable_ch0 == true and enable_ch1 == true) @@ -100,26 +107,34 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* n_channels = 2; } + + for (int n = 0; n < n_channels; n++) + { + if (n == 0) inverted_spectrum_vec.push_back(inverted_spectrum_ch0_); + if (n == 1) inverted_spectrum_vec.push_back(inverted_spectrum_ch1_); + } + for (int n = 0; n < n_channels; n++) { if (ssize_ == 16) { - gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make()); + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n))); } else if (ssize_ == 8) { - gr_interleaved_char_to_complex_.push_back(gr::blocks::interleaved_char_to_complex::make()); unpack_short_byte.push_back(make_unpack_short_byte_samples()); + gr_char_to_short_.push_back(gr::blocks::char_to_short::make()); + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n))); } else if (ssize_ == 4) { - gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false)); + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n))); unpack_byte_fourbits.push_back(make_unpack_byte_4bit_samples()); unpack_short_byte.push_back(make_unpack_short_byte_samples()); } else if (ssize_ == 2) { - gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false)); + gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n))); unpack_byte_twobits.push_back(make_unpack_byte_2bit_cpx_samples()); unpack_short_byte.push_back(make_unpack_short_byte_samples()); } @@ -169,11 +184,12 @@ void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) else if (ssize_ == 8) { top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0); - top_block->connect(unpack_short_byte.at(n), 0, gr_interleaved_char_to_complex_.at(n), 0); - DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n; + top_block->connect(unpack_short_byte.at(n), 0, gr_char_to_short_.at(n), 0); + top_block->connect(gr_char_to_short_.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex_ for channel " << n; if (dump_) { - top_block->connect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0); + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); DLOG(INFO) << "connected source to file sink"; } } @@ -231,13 +247,14 @@ void Ad936xCustomSignalSource::disconnect(gr::top_block_sptr top_block) } else if (ssize_ == 8) { - top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0); - top_block->connect(unpack_short_byte.at(n), 0, unpack_byte_fourbits.at(n), 0); - DLOG(INFO) << "disconnect ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n; + top_block->disconnect(ad936x_iio_source, n, unpack_short_byte.at(n), 0); + top_block->disconnect(unpack_short_byte.at(n), 0, gr_char_to_short_.at(n), 0); + top_block->disconnect(gr_char_to_short_.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); + DLOG(INFO) << "disconnect ad936x_iio_source source to gr_interleaved_short_to_complex_ for channel " << n; if (dump_) { - top_block->disconnect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "disconnect source to file sink"; + top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; } } else if (ssize_ == 4) @@ -293,7 +310,7 @@ gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block() } else if (ssize_ == 8) { - return gr_interleaved_char_to_complex_.at(0); + return gr_interleaved_short_to_complex_.at(0); } else if (ssize_ == 4) { @@ -317,7 +334,7 @@ gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block(int RF_channel) } else if (ssize_ == 8) { - return gr_interleaved_char_to_complex_.at(RF_channel); + return gr_interleaved_short_to_complex_.at(RF_channel); } else if (ssize_ == 4) { diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h index 88bba68ef..11c5823a0 100644 --- a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h @@ -24,8 +24,9 @@ #include "unpack_byte_2bit_cpx_samples.h" #include "unpack_byte_4bit_samples.h" #include "unpack_short_byte_samples.h" +#include #include -#include +// #include #include #include #include @@ -73,8 +74,9 @@ private: std::vector sink_; std::vector filename_vec_; + std::vector gr_char_to_short_; std::vector gr_interleaved_short_to_complex_; - std::vector gr_interleaved_char_to_complex_; + // std::vector gr_interleaved_char_to_complex_; std::vector unpack_short_byte; std::vector unpack_byte_fourbits; std::vector unpack_byte_twobits; @@ -109,8 +111,10 @@ private: bool spattern_; bool inverted_spectrum_ch0_; bool inverted_spectrum_ch1_; + double lo_attenuation_db_; + bool high_side_lo_; - + std::vector inverted_spectrum_vec; int n_channels; }; diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index 77ebd64bc..a54a5a966 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -53,7 +53,9 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( int fe_ctlport_, int ssize_, int bshift_, - bool spattern_) + bool spattern_, + double lo_attenuation_db_, + bool high_side_lo_) { return ad936x_iio_source_sptr(new ad936x_iio_source( pluto_uri_, @@ -76,7 +78,9 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( fe_ctlport_, ssize_, bshift_, - spattern_)); + spattern_, + lo_attenuation_db_, + high_side_lo_)); } void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector *files_out) @@ -116,9 +120,11 @@ ad936x_iio_source::ad936x_iio_source( int fe_ctlport_, int ssize_, int bshift_, - bool spattern_) : gr::block("ad936x_iio_source", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(1, 4, sizeof(int16_t))) + bool spattern_, + double lo_attenuation_db_, + bool high_side_lo_) : gr::block("ad936x_iio_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 4, sizeof(int16_t))) { ad936x_custom = std::make_unique(0, 0); try @@ -137,7 +143,9 @@ ad936x_iio_source::ad936x_iio_source( rf_gain_rx1_, enable_ch0, enable_ch1, - freq_2ch) == true) + freq_2ch, + lo_attenuation_db_, + high_side_lo_) == true) { std::cout << "ad936x_iio_source HW configured OK!\n"; diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h index 7285ce15b..f3856b3d6 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h @@ -64,7 +64,9 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( int fe_ctlport_, int ssize_, int bshift_, - bool spattern_); + bool spattern_, + double lo_attenuation_db_, + bool high_side_lo_); /*! * \brief This class implements conversion between Labsat 2, 3 and 3 Wideband @@ -107,7 +109,9 @@ private: int fe_ctlport_, int ssize_, int bshift_, - bool spattern_); + bool spattern_, + double lo_attenuation_db_, + bool high_side_lo_); ad936x_iio_source( std::string pluto_uri_, @@ -130,7 +134,9 @@ private: int fe_ctlport_, int ssize_, int bshift_, - bool spattern_); + bool spattern_, + double lo_attenuation_db_, + bool high_side_lo_); void ad9361_channel_demux_to_buffer(ad936x_iio_samples *samples_in, int nchannels, gr_vector_void_star &output_items); diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 92be896c4..3357a59d6 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -410,7 +410,9 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch) + long long freq_2ch, + double lo_attenuation_db_, + bool high_side_lo_) { if (check_device() == false) return false; @@ -510,17 +512,32 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, if (enable_ch1 == true and enable_ch0 == true and freq_ != freq_2ch) { std::cout << "Two channels enabled with different frequencies, enabling the external RF transverter board:\n"; - long long int delta_freq_hz = freq_2ch - freq_; - if (delta_freq_hz < 0) + long long int lo_freq_hz = 0; + if (high_side_lo_ == false) { - std::cout << "Configuration problem: 2nd channel frequency is " << freq_2ch << " [Hz], must be higher than main channel (" << freq_ << " [Hz])\n"; - return false; + std::cout << "Using LOW SIDE Local Oscillator (F_RF > F_LO)\n"; + lo_freq_hz = freq_2ch - freq_; + if (lo_freq_hz < 0) + { + std::cout << "Configuration problem: 2nd channel frequency is " << freq_2ch << " [Hz], must be higher than main channel (" << freq_ << " [Hz])\n"; + return false; + } + } + else + { + std::cout << "Using HIGH SIDE Local Oscillator (F_RF < F_LO), consider baseband spectrum inversion.\n"; + lo_freq_hz = freq_2ch + freq_; + if (lo_freq_hz < 0) + { + std::cout << "Configuration problem: 2nd channel frequency is " << freq_2ch << " [Hz], must be higher than main channel (" << freq_ << " [Hz])\n"; + return false; + } } - std::cout << "Configuring DDS Local Oscillator generation. LO Freq. is " << delta_freq_hz << " [Hz]\n"; + std::cout << "Configuring DDS Local Oscillator generation. LO Freq. is " << lo_freq_hz << " [Hz]\n"; PlutoTxEnable(true); - config_ad9361_dds(delta_freq_hz, - 0, + config_ad9361_dds(lo_freq_hz, + lo_attenuation_db_, 0, 0.9, 0, @@ -532,6 +549,30 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, PlutoTxEnable(false); //power down the TX LO to reduce interferences } + + int set_filter_ret = ad9361_set_bb_rate_custom_filter_auto(phy, sample_rate_sps); + if (set_filter_ret != 0) + { + std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + } + + //testing: set manual RX filter chain + // unsigned long RX_analog_bb_lpf_stop_hz = 1000000; + // unsigned long TX_analog_bb_lpf_stop_hz = 1000000; + // + // unsigned long FIR_lpf_passband_hz = 1000000; + // unsigned long FIR_lpf_stopband_hz = 1200000; + // int set_filter_ret = ad9361_set_bb_rate_custom_filter_manual(phy, + // sample_rate_sps, + // FIR_lpf_passband_hz, + // FIR_lpf_stopband_hz, + // RX_analog_bb_lpf_stop_hz, + // TX_analog_bb_lpf_stop_hz); + // if (set_filter_ret != 0) + // { + // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + // } + if (enable_ch0 == true) { n_channels++; @@ -555,12 +596,12 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, no_errors = false; } - ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); - if (ret < 0) - { - std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; - no_errors = false; - } + // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + // if (ret < 0) + // { + // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + // no_errors = false; + // } long long set_rf_bw; ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); @@ -605,12 +646,24 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, no_errors = false; } - ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + // if (ret < 0) + // { + // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + // no_errors = false; + // } + + long long set_rf_bw; + ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); if (ret < 0) { - std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; no_errors = false; } + else + { + std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; + } if (setRXGain(1, gain_mode_rx1_, rf_gain_rx1_) == false) { @@ -619,29 +672,6 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, } } - int set_filter_ret = ad9361_set_bb_rate_custom_filter_auto(phy, sample_rate_sps); - if (set_filter_ret != 0) - { - std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; - } - - //testing: set manual RX filter chain - // unsigned long RX_analog_bb_lpf_stop_hz = 1000000; - // unsigned long TX_analog_bb_lpf_stop_hz = 1000000; - // - // unsigned long FIR_lpf_passband_hz = 1000000; - // unsigned long FIR_lpf_stopband_hz = 1200000; - // int set_filter_ret = ad9361_set_bb_rate_custom_filter_manual(phy, - // sample_rate_sps, - // FIR_lpf_passband_hz, - // FIR_lpf_stopband_hz, - // RX_analog_bb_lpf_stop_hz, - // TX_analog_bb_lpf_stop_hz); - // if (set_filter_ret != 0) - // { - // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; - // } - std::cout << "AD936x Front-end configuration summary: \n"; std::cout << "RF frequency tunned in AD936x: " << freq_ << " [Hz]\n"; std::cout << "Baseband sampling frequency: " << sample_rate_sps << " [SPS]\n"; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.h b/src/algorithms/signal_source/libs/ad936x_iio_custom.h index 4d95fb340..cbf5e65e7 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.h @@ -53,7 +53,9 @@ public: double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch); + long long freq_2ch, + double lo_attenuation_db_, + bool high_side_lo_); bool calibrate(int ch, double bw_hz); From db2addd9bc4e5433b20dcd560e1efc8ccdad29a5 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 30 Aug 2022 16:50:38 +0200 Subject: [PATCH 18/31] AD936x custom source switch from custom to default baseband filters --- .../signal_source/libs/ad936x_iio_custom.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 3357a59d6..705180ef7 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -549,13 +549,18 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, PlutoTxEnable(false); //power down the TX LO to reduce interferences } - - int set_filter_ret = ad9361_set_bb_rate_custom_filter_auto(phy, sample_rate_sps); + int set_filter_ret = ad9361_set_bb_rate(phy, sample_rate_sps); if (set_filter_ret != 0) { - std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + std::cout << "Warning: Unable to set AD936x ad9361_set_bb_rate parameters!\n"; } + // int set_filter_ret = ad9361_set_bb_rate_custom_filter_auto(phy, sample_rate_sps); + // if (set_filter_ret != 0) + // { + // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; + // } + //testing: set manual RX filter chain // unsigned long RX_analog_bb_lpf_stop_hz = 1000000; // unsigned long TX_analog_bb_lpf_stop_hz = 1000000; From dd1ce7893c0da4835be653ec6c8e5b3c2d7e41b7 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 13 Sep 2022 17:34:23 +0200 Subject: [PATCH 19/31] Adding ad936x custom source optional interchannel delay compensation --- .../adapters/ad936x_custom_signal_source.cc | 297 +++++++++++++++--- .../adapters/ad936x_custom_signal_source.h | 6 + .../gnuradio_blocks/ad936x_iio_source.cc | 12 +- .../gnuradio_blocks/ad936x_iio_source.h | 9 +- .../signal_source/libs/ad936x_iio_custom.cc | 88 +++--- .../signal_source/libs/ad936x_iio_custom.h | 4 +- 6 files changed, 314 insertions(+), 102 deletions(-) diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc index 5229405dd..067bf0e3d 100644 --- a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc @@ -62,7 +62,10 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* inverted_spectrum_ch0_(configuration->property(role + ".inverted_spectrum_ch0", false)), inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false)), lo_attenuation_db_(configuration->property(role + ".lo_attenuation_db", 6.0)), - high_side_lo_(configuration->property(role + ".high_side_lo", false)) + high_side_lo_(configuration->property(role + ".high_side_lo", false)), + tx_lo_channel_(configuration->property(role + ".tx_lo_channel", 1)), + rx0_to_rx1_delay_ns_(configuration->property(role + ".rx0_to_rx1_delay_ns", 0.0)) + { if (item_type_ == "gr_complex") @@ -99,7 +102,8 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* bshift_, spattern_, lo_attenuation_db_, - high_side_lo_); + high_side_lo_, + tx_lo_channel_); n_channels = 1; if (enable_ch0 == true and enable_ch1 == true) @@ -107,6 +111,42 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* n_channels = 2; } + int delay_samples = 0; + if (n_channels == 2 and rx0_to_rx1_delay_ns_ != 0.0) + { + double ts = 1.0 / static_cast(sample_rate_); + delay_samples = std::round(ts * rx0_to_rx1_delay_ns_ * 1e-9); + if (delay_samples != 0) + { + delay_enabled = true; + if (delay_samples > 0) + { + apply_delay_on_rx0 = true; + LOG(INFO) << " Instantiating delay of rx0 equal to " << delay_samples << " samples."; + } + else + { + // delay applied to rx1 instead. + apply_delay_on_rx0 = false; + delay_samples = -delay_samples; + LOG(INFO) << " Instantiating delay of rx1 equal to " << delay_samples << " samples."; + } + } + else + { + LOG(INFO) << " Specified rx0_to_rx1 delay is smaller than the front-end sample period."; + } + } + else + { + apply_delay_on_rx0 = false; + delay_enabled = false; + } + + if (delay_enabled == true) + { + gr_delay = gr::blocks::delay::make(sizeof(gr_complex), delay_samples); + } for (int n = 0; n < n_channels; n++) { @@ -175,10 +215,44 @@ void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) { top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; - if (dump_) + if (delay_enabled == true) { - top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; + if (n == 0 and apply_delay_on_rx0 == true) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else if (n == 1 and apply_delay_on_rx0 == false) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } else if (ssize_ == 8) @@ -186,11 +260,44 @@ void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0); top_block->connect(unpack_short_byte.at(n), 0, gr_char_to_short_.at(n), 0); top_block->connect(gr_char_to_short_.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); - DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex_ for channel " << n; - if (dump_) + if (delay_enabled == true) { - top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; + if (n == 0 and apply_delay_on_rx0 == true) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else if (n == 1 and apply_delay_on_rx0 == false) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } else if (ssize_ == 4) @@ -199,10 +306,45 @@ void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) top_block->connect(unpack_short_byte.at(n), 0, unpack_byte_fourbits.at(n), 0); top_block->connect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; - if (dump_) + + if (delay_enabled == true) { - top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; + if (n == 0 and apply_delay_on_rx0 == true) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else if (n == 1 and apply_delay_on_rx0 == false) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } else if (ssize_ == 2) @@ -211,20 +353,91 @@ void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block) top_block->connect(unpack_short_byte.at(n), 0, unpack_byte_twobits.at(n), 0); top_block->connect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0); DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n; - if (dump_) + + if (delay_enabled == true) { - top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; + if (n == 0 and apply_delay_on_rx0 == true) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else if (n == 1 and apply_delay_on_rx0 == false) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } + else + { + if (dump_) + + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } else { top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0); DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n; - if (dump_) + + if (delay_enabled == true) { - top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; + if (n == 0 and apply_delay_on_rx0 == true) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else if (n == 1 and apply_delay_on_rx0 == false) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0); + DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n; + if (dump_) + { + top_block->connect(gr_delay, 0, sink_.at(n), 0); + DLOG(INFO) << "connected delayed source to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } + } + else + { + if (dump_) + { + top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } } @@ -304,45 +517,25 @@ gr::basic_block_sptr Ad936xCustomSignalSource::get_left_block() gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block() { - if (ssize_ == 16) - { - return gr_interleaved_short_to_complex_.at(0); - } - else if (ssize_ == 8) - { - return gr_interleaved_short_to_complex_.at(0); - } - else if (ssize_ == 4) - { - return gr_interleaved_short_to_complex_.at(0); - } - else if (ssize_ == 2) - { - return gr_interleaved_short_to_complex_.at(0); - } - else - { - return gr_interleaved_short_to_complex_.at(0); - } + return gr_interleaved_short_to_complex_.at(0); } gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block(int RF_channel) { - if (ssize_ == 16) + if (delay_enabled == true) { - return gr_interleaved_short_to_complex_.at(RF_channel); - } - else if (ssize_ == 8) - { - return gr_interleaved_short_to_complex_.at(RF_channel); - } - else if (ssize_ == 4) - { - return gr_interleaved_short_to_complex_.at(RF_channel); - } - else if (ssize_ == 2) - { - return gr_interleaved_short_to_complex_.at(RF_channel); + if (RF_channel == 0 and apply_delay_on_rx0 == true) + { + return gr_delay; + } + else if (RF_channel == 1 and apply_delay_on_rx0 == false) + { + return gr_delay; + } + else + { + return gr_interleaved_short_to_complex_.at(RF_channel); + } } else { diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h index 11c5823a0..4d4ae813c 100644 --- a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.h @@ -27,6 +27,7 @@ #include #include // #include +#include #include #include #include @@ -74,6 +75,7 @@ private: std::vector sink_; std::vector filename_vec_; + gr::blocks::delay::sptr gr_delay; std::vector gr_char_to_short_; std::vector gr_interleaved_short_to_complex_; // std::vector gr_interleaved_char_to_complex_; @@ -113,6 +115,10 @@ private: bool inverted_spectrum_ch1_; double lo_attenuation_db_; bool high_side_lo_; + int tx_lo_channel_; + double rx0_to_rx1_delay_ns_; + bool delay_enabled; + bool apply_delay_on_rx0; std::vector inverted_spectrum_vec; int n_channels; diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index a54a5a966..ffaae3e9c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -55,7 +55,8 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( int bshift_, bool spattern_, double lo_attenuation_db_, - bool high_side_lo_) + bool high_side_lo_, + int tx_lo_channel_) { return ad936x_iio_source_sptr(new ad936x_iio_source( pluto_uri_, @@ -80,7 +81,8 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( bshift_, spattern_, lo_attenuation_db_, - high_side_lo_)); + high_side_lo_, + tx_lo_channel_)); } void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector *files_out) @@ -122,7 +124,8 @@ ad936x_iio_source::ad936x_iio_source( int bshift_, bool spattern_, double lo_attenuation_db_, - bool high_side_lo_) : gr::block("ad936x_iio_source", + bool high_side_lo_, + int tx_lo_channel_) : gr::block("ad936x_iio_source", gr::io_signature::make(0, 0, 0), gr::io_signature::make(1, 4, sizeof(int16_t))) { @@ -145,7 +148,8 @@ ad936x_iio_source::ad936x_iio_source( enable_ch1, freq_2ch, lo_attenuation_db_, - high_side_lo_) == true) + high_side_lo_, + tx_lo_channel_) == true) { std::cout << "ad936x_iio_source HW configured OK!\n"; diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h index f3856b3d6..411906a3e 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h @@ -66,7 +66,8 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( int bshift_, bool spattern_, double lo_attenuation_db_, - bool high_side_lo_); + bool high_side_lo_, + int tx_lo_channel_); /*! * \brief This class implements conversion between Labsat 2, 3 and 3 Wideband @@ -111,7 +112,8 @@ private: int bshift_, bool spattern_, double lo_attenuation_db_, - bool high_side_lo_); + bool high_side_lo_, + int tx_lo_channel_); ad936x_iio_source( std::string pluto_uri_, @@ -136,7 +138,8 @@ private: int bshift_, bool spattern_, double lo_attenuation_db_, - bool high_side_lo_); + bool high_side_lo_, + int tx_lo_channel_); void ad9361_channel_demux_to_buffer(ad936x_iio_samples *samples_in, int nchannels, gr_vector_void_star &output_items); diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 705180ef7..c1bb56f5e 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -258,17 +258,39 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, // ENABLE DDS on TX1 // Configure LO channel std::vector params_phy; + std::vector params_dds; params_phy.push_back("out_altvoltage1_TX_LO_frequency=" + std::to_string(freq_rf_tx_hz_)); double disabled_tx_attenuation = 89.75; - if (channel == 1) + if (channel == 0) { params_phy.push_back("out_voltage0_hardwaregain=" + std::to_string(-tx_attenuation_db_)); //disable the other TX params_phy.push_back("out_voltage1_hardwaregain=" + std::to_string(-disabled_tx_attenuation)); + + configure_params(phy, params_phy); + + //DDS TX CH1 I (tone #1) + params_dds.push_back("out_altvoltage0_TX1_I_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage0_TX1_I_F1_raw=1"); + //DDS TX CH1 Q (tone #1) + params_dds.push_back("out_altvoltage2_TX1_Q_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage2_TX1_Q_F1_raw=1"); + + configure_params(dds_dev, params_dds); } else { @@ -277,46 +299,29 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, //disable the other TX params_phy.push_back("out_voltage0_hardwaregain=" + std::to_string(-disabled_tx_attenuation)); + + configure_params(phy, params_phy); + + //DDS TX CH2 I (tone #1) + params_dds.push_back("out_altvoltage4_TX2_I_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage4_TX2_I_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0)); + params_dds.push_back("out_altvoltage4_TX2_I_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage4_TX2_I_F1_raw=1"); + //DDS TX CH2 Q (tone #1) + params_dds.push_back("out_altvoltage6_TX2_Q_F1_frequency=" + + std::to_string(freq_dds_tx_hz_)); + params_dds.push_back("out_altvoltage6_TX2_Q_F1_phase=" + + std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); + params_dds.push_back("out_altvoltage6_TX2_Q_F1_scale=" + + std::to_string(scale_dds_)); + params_dds.push_back("out_altvoltage6_TX2_Q_F1_raw=1"); + + configure_params(dds_dev, params_dds); } - configure_params(phy, params_phy); - std::vector params_dds; - - //DDS TX CH1 I (tone #1) - // params_dds.push_back("out_altvoltage0_TX1_I_F1_frequency=" + - // std::to_string(freq_dds_tx_hz_)); - // params_dds.push_back("out_altvoltage0_TX1_I_F1_phase=" + - // std::to_string(phase_dds_deg_ * 1000.0)); - // params_dds.push_back("out_altvoltage0_TX1_I_F1_scale=" + - // std::to_string(scale_dds_)); - // params_dds.push_back("out_altvoltage0_TX1_I_F1_raw=1"); - // //DDS TX CH1 Q (tone #1) - // params_dds.push_back("out_altvoltage2_TX1_Q_F1_frequency=" + - // std::to_string(freq_dds_tx_hz_)); - // params_dds.push_back("out_altvoltage2_TX1_Q_F1_phase=" + - // std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); - // params_dds.push_back("out_altvoltage2_TX1_Q_F1_scale=" + - // std::to_string(scale_dds_)); - // params_dds.push_back("out_altvoltage2_TX1_Q_F1_raw=1"); - - //DDS TX CH2 I (tone #1) - params_dds.push_back("out_altvoltage4_TX2_I_F1_frequency=" + - std::to_string(freq_dds_tx_hz_)); - params_dds.push_back("out_altvoltage4_TX2_I_F1_phase=" + - std::to_string(phase_dds_deg_ * 1000.0)); - params_dds.push_back("out_altvoltage4_TX2_I_F1_scale=" + - std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage4_TX2_I_F1_raw=1"); - //DDS TX CH2 Q (tone #1) - params_dds.push_back("out_altvoltage6_TX2_Q_F1_frequency=" + - std::to_string(freq_dds_tx_hz_)); - params_dds.push_back("out_altvoltage6_TX2_Q_F1_phase=" + - std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); - params_dds.push_back("out_altvoltage6_TX2_Q_F1_scale=" + - std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage6_TX2_Q_F1_raw=1"); - - configure_params(dds_dev, params_dds); return true; } @@ -412,7 +417,8 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, bool enable_ch1, long long freq_2ch, double lo_attenuation_db_, - bool high_side_lo_) + bool high_side_lo_, + int tx_lo_channel_) { if (check_device() == false) return false; @@ -541,7 +547,7 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, 0, 0.9, 0, - 2); + tx_lo_channel_); std::cout << "Configuring DDS Local Oscillator generation DONE\n"; } else diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.h b/src/algorithms/signal_source/libs/ad936x_iio_custom.h index cbf5e65e7..de36f5b5b 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.h @@ -55,7 +55,8 @@ public: bool enable_ch1, long long freq_2ch, double lo_attenuation_db_, - bool high_side_lo_); + bool high_side_lo_, + int tx_lo_channel_); bool calibrate(int ch, double bw_hz); @@ -79,7 +80,6 @@ public: void pop_sample_buffer(std::shared_ptr ¤t_buffer); void push_sample_buffer(std::shared_ptr ¤t_buffer); - int n_channels; private: From 205583bb277de1d911ee8e91a1c9a4e85167acae Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Thu, 22 Sep 2022 15:15:07 +0200 Subject: [PATCH 20/31] Update ad936x iio custom lib --- .../signal_source/libs/ad936x_iio_custom.cc | 122 +++++++++--------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index c1bb56f5e..efd67e778 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -512,9 +512,6 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, no_errors = false; } - - std::cout << "no_errors: " << no_errors << "\n"; - if (enable_ch1 == true and enable_ch0 == true and freq_ != freq_2ch) { std::cout << "Two channels enabled with different frequencies, enabling the external RF transverter board:\n"; @@ -583,10 +580,8 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, // { // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; // } - if (enable_ch0 == true) { - n_channels++; std::cerr << "* Get AD9361 Phy RX channel 0...\n"; std::stringstream name; name.str(""); @@ -599,44 +594,45 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, std::cerr << "Could not find AD9361 phy channel: " << name.str() << "\n"; no_errors = false; } - - ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); - if (ret < 0) - { - std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; - no_errors = false; - } - - // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); - // if (ret < 0) - // { - // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; - // no_errors = false; - // } - - long long set_rf_bw; - ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); - if (ret < 0) - { - std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; - no_errors = false; - } else { - std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; - } + ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); + if (ret < 0) + { + std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; + no_errors = false; + } + + // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + // if (ret < 0) + // { + // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + // no_errors = false; + // } + + long long set_rf_bw; + ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); + if (ret < 0) + { + std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; + no_errors = false; + } + else + { + std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; + } - if (setRXGain(0, gain_mode_rx0_, rf_gain_rx0_) == false) - { - std::cerr << "Info: setRXGain read returned false \n"; - no_errors = false; + if (setRXGain(0, gain_mode_rx0_, rf_gain_rx0_) == false) + { + std::cerr << "Info: setRXGain read returned false \n"; + no_errors = false; + } } } if (enable_ch1 == true) { - n_channels++; std::cerr << "* Get AD9361 Phy RX channel 1...\n"; std::stringstream name; name.str(""); @@ -649,37 +645,39 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, std::cerr << "Could not find AD9361 phy channel: " << name.str() << "\n"; no_errors = false; } - - ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); - if (ret < 0) - { - std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; - no_errors = false; - } - - // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); - // if (ret < 0) - // { - // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; - // no_errors = false; - // } - - long long set_rf_bw; - ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); - if (ret < 0) - { - std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; - no_errors = false; - } else { - std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; - } + ret = iio_channel_attr_write(phy_ch, "rf_port_select", rf_port_select_.c_str()); + if (ret < 0) + { + std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; + no_errors = false; + } - if (setRXGain(1, gain_mode_rx1_, rf_gain_rx1_) == false) - { - std::cerr << "Info: setRXGain read returned false \n"; - no_errors = false; + // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); + // if (ret < 0) + // { + // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; + // no_errors = false; + // } + + long long set_rf_bw; + ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); + if (ret < 0) + { + std::cerr << "Warning: rf_bandwidth read returned: " << ret << "\n"; + no_errors = false; + } + else + { + std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; + } + + if (setRXGain(1, gain_mode_rx1_, rf_gain_rx1_) == false) + { + std::cerr << "Info: setRXGain read returned false \n"; + no_errors = false; + } } } From be2e5d8d5e495665f0d4519d6299df9a5b63b8cf Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Fri, 9 Jun 2023 14:09:18 +0200 Subject: [PATCH 21/31] Adding c2bits sample stream to UDP custom source --- .../gr_complex_ip_packet_source.cc | 251 +++++++++++------- .../gr_complex_ip_packet_source.h | 4 +- 2 files changed, 163 insertions(+), 92 deletions(-) diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc index 6cead4e46..20f829e6a 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -30,6 +30,11 @@ const int FIFO_SIZE = 1472000; +struct byte_2bit_struct +{ + signed two_bit_sample : 2; // <- 2 bits wide only +}; + /* 4 bytes IP address */ typedef struct gr_ip_address { @@ -120,6 +125,11 @@ Gr_Complex_Ip_Packet_Source::Gr_Complex_Ip_Packet_Source(std::string src_device, d_wire_sample_type = 1; d_bytes_per_sample = d_n_baseband_channels * 2; } + else if (wire_sample_type == "c2bits") + { + d_wire_sample_type = 5; + d_bytes_per_sample = d_n_baseband_channels; + } else if (wire_sample_type == "c4bits") { d_wire_sample_type = 2; @@ -183,7 +193,8 @@ bool Gr_Complex_Ip_Packet_Source::stop() bool Gr_Complex_Ip_Packet_Source::open() { std::array errbuf{}; - boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + gr::thread::scoped_lock guard(d_setlock); // open device for reading descr = pcap_open_live(d_src_device.c_str(), 1500, 1, 1000, errbuf.data()); if (descr == nullptr) @@ -239,7 +250,7 @@ void Gr_Complex_Ip_Packet_Source::static_pcap_callback(u_char *args, const struc void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char *args, __attribute__((unused)) const struct pcap_pkthdr *pkthdr, const u_char *packet) { - boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function const gr_ip_header *ih; const gr_udp_header *uh; @@ -321,107 +332,164 @@ void Gr_Complex_Ip_Packet_Source::my_pcap_loop_thread(pcap_t *pcap_handle) void Gr_Complex_Ip_Packet_Source::demux_samples(const gr_vector_void_star &output_items, int num_samples_readed) { - for (int n = 0; n < num_samples_readed; n++) + if (d_wire_sample_type == 5) { - switch (d_wire_sample_type) + //interleaved 2-bit I 2-bit Q samples packed in bytes: 1 byte -> 2 complex samples + int nsample = 0; + byte_2bit_struct sample{}; // <- 2 bits wide only + int real; + int imag; + for (int nbyte = 0; nbyte < num_samples_readed / 2; nbyte++) { - case 1: // interleaved byte samples for (const auto &output_item : output_items) { - int8_t real; - int8_t imag; - real = fifo_buff[fifo_read_ptr++]; - imag = fifo_buff[fifo_read_ptr++]; + // Read packed input sample (1 byte = 2 complex samples) + // * Packing Order + // * Most Significant Nibble - Sample n + // * Least Significant Nibble - Sample n+1 + // * Bit Packing order in Nibble Q1 Q0 I1 I0 + // normal + int8_t c = fifo_buff[fifo_read_ptr++]; + + // Q[n] + sample.two_bit_sample = (c >> 6) & 3; + imag = (2 * static_cast(sample.two_bit_sample) + 1); + // I[n] + sample.two_bit_sample = (c >> 4) & 3; + real = (2 * static_cast(sample.two_bit_sample) + 1); + if (d_IQ_swap) { - static_cast(output_item)[n] = gr_complex(real, imag); + static_cast(output_item)[nsample] = gr_complex(real, imag); } else { - static_cast(output_item)[n] = gr_complex(imag, real); - } - } - break; - case 2: // 4-bit samples - for (const auto &output_item : output_items) - { - int8_t real; - int8_t imag; - uint8_t tmp_char2; - tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F; - if (tmp_char2 >= 8) - { - real = 2 * (tmp_char2 - 16) + 1; - } - else - { - real = 2 * tmp_char2 + 1; - } - tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4; - tmp_char2 = tmp_char2 & 0x0F; - if (tmp_char2 >= 8) - { - imag = 2 * (tmp_char2 - 16) + 1; - } - else - { - imag = 2 * tmp_char2 + 1; + static_cast(output_item)[nsample] = gr_complex(imag, real); } + + + // Q[n+1] + sample.two_bit_sample = (c >> 2) & 3; + imag = (2 * static_cast(sample.two_bit_sample) + 1); + // I[n+1] + sample.two_bit_sample = c & 3; + real = (2 * static_cast(sample.two_bit_sample) + 1); + if (d_IQ_swap) { - static_cast(output_item)[n] = gr_complex(imag, real); + static_cast(output_item)[nsample + 1] = gr_complex(real, imag); } else { - static_cast(output_item)[n] = gr_complex(real, imag); + static_cast(output_item)[nsample + 1] = gr_complex(imag, real); } } - break; - case 3: // interleaved float samples - for (const auto &output_item : output_items) - { - float real; - float imag; - memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real)); - fifo_read_ptr += 4; // Four bytes in float - memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag)); - fifo_read_ptr += 4; // Four bytes in float - if (d_IQ_swap) - { - static_cast(output_item)[n] = gr_complex(real, imag); - } - else - { - static_cast(output_item)[n] = gr_complex(imag, real); - } - } - break; - case 4: // interleaved short samples - for (const auto &output_item : output_items) - { - int16_t real; - int16_t imag; - memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real)); - fifo_read_ptr += 2; // two bytes in short - memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag)); - fifo_read_ptr += 2; // two bytes in short - if (d_IQ_swap) - { - static_cast(output_item)[n] = gr_complex(real, imag); - } - else - { - static_cast(output_item)[n] = gr_complex(imag, real); - } - } - break; - default: - std::cout << "Unknown wire sample type\n"; - exit(0); } - if (fifo_read_ptr == FIFO_SIZE) + } + else + { + for (int n = 0; n < num_samples_readed; n++) { - fifo_read_ptr = 0; + switch (d_wire_sample_type) + { + case 1: // interleaved byte samples + for (const auto &output_item : output_items) + { + int8_t real; + int8_t imag; + real = fifo_buff[fifo_read_ptr++]; + imag = fifo_buff[fifo_read_ptr++]; + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + else + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + } + break; + case 2: // 4-bit samples + for (const auto &output_item : output_items) + { + int8_t real; + int8_t imag; + uint8_t tmp_char2; + tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F; + if (tmp_char2 >= 8) + { + real = 2 * (tmp_char2 - 16) + 1; + } + else + { + real = 2 * tmp_char2 + 1; + } + tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4; + tmp_char2 = tmp_char2 & 0x0F; + if (tmp_char2 >= 8) + { + imag = 2 * (tmp_char2 - 16) + 1; + } + else + { + imag = 2 * tmp_char2 + 1; + } + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + else + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + } + break; + case 3: // interleaved float samples + for (const auto &output_item : output_items) + { + float real; + float imag; + memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real)); + fifo_read_ptr += 4; // Four bytes in float + memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag)); + fifo_read_ptr += 4; // Four bytes in float + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + else + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + } + break; + case 4: // interleaved short samples + for (const auto &output_item : output_items) + { + int16_t real; + int16_t imag; + memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real)); + fifo_read_ptr += 2; // two bytes in short + memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag)); + fifo_read_ptr += 2; // two bytes in short + if (d_IQ_swap) + { + static_cast(output_item)[n] = gr_complex(real, imag); + } + else + { + static_cast(output_item)[n] = gr_complex(imag, real); + } + } + break; + default: + std::cout << "Unknown wire sample type\n"; + exit(0); + } + if (fifo_read_ptr == FIFO_SIZE) + { + fifo_read_ptr = 0; + } } } } @@ -432,7 +500,7 @@ int Gr_Complex_Ip_Packet_Source::work(int noutput_items, gr_vector_void_star &output_items) { // send samples to next GNU Radio block - boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function if (fifo_items == 0) { return 0; @@ -446,21 +514,24 @@ int Gr_Complex_Ip_Packet_Source::work(int noutput_items, int num_samples_readed; int bytes_requested; - bytes_requested = noutput_items * d_bytes_per_sample; + bytes_requested = static_cast(static_cast(noutput_items) * d_bytes_per_sample); if (bytes_requested < fifo_items) { num_samples_readed = noutput_items; // read all + // update fifo items + fifo_items = fifo_items - bytes_requested; } else { - num_samples_readed = fifo_items / d_bytes_per_sample; // read what we have + num_samples_readed = static_cast(static_cast(fifo_items) / d_bytes_per_sample); // read what we have + bytes_requested = fifo_items; + // update fifo items + fifo_items = 0; } - bytes_requested = num_samples_readed * d_bytes_per_sample; + // read all in a single loop demux_samples(output_items, num_samples_readed); // it also increases the fifo read pointer - // update fifo items - fifo_items = fifo_items - bytes_requested; for (uint64_t n = 0; n < output_items.size(); n++) { diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h index c24ee5417..9f8939904 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h @@ -83,7 +83,7 @@ private: bool open(); boost::thread *d_pcap_thread; - boost::mutex d_mutex; + //boost::mutex d_mutex; struct sockaddr_in si_me { }; @@ -98,7 +98,7 @@ private: int d_udp_port; int d_n_baseband_channels; int d_wire_sample_type; - int d_bytes_per_sample; + float d_bytes_per_sample; bool d_IQ_swap; }; From 36e709dda646484c44eb6591db1d9e429c624922 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 4 Jul 2023 13:09:45 +0200 Subject: [PATCH 22/31] Adding a simple PVT Holonomic Kalman filter for position and velocity --- src/algorithms/PVT/adapters/rtklib_pvt.cc | 7 + .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 7 +- .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 1 - src/algorithms/PVT/libs/CMakeLists.txt | 2 + src/algorithms/PVT/libs/pvt_conf.h | 7 + src/algorithms/PVT/libs/pvt_kf.cc | 132 ++++++++++++++++++ src/algorithms/PVT/libs/pvt_kf.h | 66 +++++++++ src/algorithms/PVT/libs/rtklib_solver.cc | 51 ++++++- src/algorithms/PVT/libs/rtklib_solver.h | 7 +- .../pvt/nmea_printer_test.cc | 5 +- .../pvt/rinex_printer_test.cc | 41 ++++-- .../pvt/rtklib_solver_test.cc | 6 +- 12 files changed, 305 insertions(+), 27 deletions(-) create mode 100644 src/algorithms/PVT/libs/pvt_kf.cc create mode 100644 src/algorithms/PVT/libs/pvt_kf.h diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index 9ce402bcc..9bf6174ab 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -74,6 +74,13 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration, // display rate pvt_output_parameters.display_rate_ms = bc::lcm(pvt_output_parameters.output_rate_ms, configuration->property(role + ".display_rate_ms", 500)); + // PVT KF settings + pvt_output_parameters.enable_pvt_kf = configuration->property(role + ".enable_pvt_kf", false); + pvt_output_parameters.measures_ecef_pos_sd_m = configuration->property(role + ".kf_measures_ecef_pos_sd_m", 1.0); + pvt_output_parameters.measures_ecef_vel_sd_ms = configuration->property(role + ".kf_measures_ecef_vel_sd_ms", 0.1); + pvt_output_parameters.system_ecef_pos_sd_m = configuration->property(role + ".kf_system_ecef_pos_sd_m", 0.01); + pvt_output_parameters.system_ecef_vel_sd_ms = configuration->property(role + ".kf_system_ecef_vel_sd_ms", 0.001); + // NMEA Printer settings pvt_output_parameters.flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false); pvt_output_parameters.nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename); diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 8f6f1648a..ab145aff4 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -178,7 +178,6 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, d_enable_rx_clock_correction(conf_.enable_rx_clock_correction), d_an_printer_enabled(conf_.an_output_enabled), d_log_timetag(conf_.log_source_timetag), - d_use_e6_for_pvt(conf_.use_e6_for_pvt), d_use_has_corrections(conf_.use_has_corrections), d_use_unhealthy_sats(conf_.use_unhealthy_sats) { @@ -535,21 +534,21 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, { // setup two PVT solvers: internal solver for rx clock and user solver // user PVT solver - d_user_pvt_solver = std::make_shared(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, d_use_e6_for_pvt); + d_user_pvt_solver = std::make_shared(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, conf_); d_user_pvt_solver->set_averaging_depth(1); d_user_pvt_solver->set_pre_2009_file(conf_.pre_2009_file); // internal PVT solver, mainly used to estimate the receiver clock rtk_t internal_rtk = rtk; internal_rtk.opt.mode = PMODE_SINGLE; // use single positioning mode in internal PVT solver - d_internal_pvt_solver = std::make_shared(internal_rtk, dump_ls_pvt_filename, d_type_of_rx, false, false, d_use_e6_for_pvt); + d_internal_pvt_solver = std::make_shared(internal_rtk, dump_ls_pvt_filename, d_type_of_rx, false, false, conf_); d_internal_pvt_solver->set_averaging_depth(1); d_internal_pvt_solver->set_pre_2009_file(conf_.pre_2009_file); } else { // only one solver, customized by the user options - d_internal_pvt_solver = std::make_shared(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, d_use_e6_for_pvt); + d_internal_pvt_solver = std::make_shared(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, conf_); d_internal_pvt_solver->set_averaging_depth(1); d_internal_pvt_solver->set_pre_2009_file(conf_.pre_2009_file); d_user_pvt_solver = d_internal_pvt_solver; diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index 747c31c65..83d1f830d 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -276,7 +276,6 @@ private: bool d_enable_has_messages; bool d_an_printer_enabled; bool d_log_timetag; - bool d_use_e6_for_pvt; bool d_use_has_corrections; bool d_use_unhealthy_sats; }; diff --git a/src/algorithms/PVT/libs/CMakeLists.txt b/src/algorithms/PVT/libs/CMakeLists.txt index 2460a3d4b..07e905a2c 100644 --- a/src/algorithms/PVT/libs/CMakeLists.txt +++ b/src/algorithms/PVT/libs/CMakeLists.txt @@ -23,6 +23,7 @@ set(PVT_LIB_SOURCES monitor_ephemeris_udp_sink.cc has_simple_printer.cc geohash.cc + pvt_kf.cc ) set(PVT_LIB_HEADERS @@ -45,6 +46,7 @@ set(PVT_LIB_HEADERS monitor_ephemeris_udp_sink.h has_simple_printer.h geohash.h + pvt_kf.h ) list(SORT PVT_LIB_HEADERS) diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index d77a0b24c..26aac201a 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -94,6 +94,13 @@ public: bool use_e6_for_pvt = true; bool use_has_corrections = true; bool use_unhealthy_sats = false; + + //PVT KF parameters + bool enable_pvt_kf = false; + double measures_ecef_pos_sd_m = 1.0; + double measures_ecef_vel_sd_ms = 0.1; + double system_ecef_pos_sd_m = 0.01; + double system_ecef_vel_sd_ms = 0.001; }; diff --git a/src/algorithms/PVT/libs/pvt_kf.cc b/src/algorithms/PVT/libs/pvt_kf.cc new file mode 100644 index 000000000..be7871974 --- /dev/null +++ b/src/algorithms/PVT/libs/pvt_kf.cc @@ -0,0 +1,132 @@ +/*! + * \file Pvt_Kf.cc + * \brief Kalman Filter for Position and Velocity + * \author Javier Arribas, 2023. jarribas(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ +#include "pvt_kf.h" +#include + + +void Pvt_Kf::init_kf(arma::vec p, arma::vec v, + double solver_interval_s, + double measures_ecef_pos_sd_m, + double measures_ecef_vel_sd_ms, + double system_ecef_pos_sd_m, + double system_ecef_vel_sd_ms) +{ + // Kalman Filter class variables + const double Ti = solver_interval_s; + + std::cout << "Ti=" << Ti << "\n"; + d_F = {{1.0, 0.0, 0.0, Ti, 0.0, 0.0}, + {0.0, 1.0, 0.0, 0.0, Ti, 0.0}, + {0.0, 0.0, 1.0, 0.0, 0.0, Ti}, + {0.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 1.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 1.0}}; + + d_H = arma::eye(6, 6); + + //measurement matrix static covariances + d_R = {{pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0), 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0), 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0)}}; + + + // system covariance matrix (static) + + d_Q = {{pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0)}}; + + // initial Kalman covariance matrix + d_P_old_old = {{pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0)}}; + + // states: position ecef [m], velocity ecef [m/s] + d_x_old_old = arma::zeros(6); + d_x_old_old.subvec(0, 2) = p; + d_x_old_old.subvec(3, 5) = v; + + initialized = true; + + DLOG(INFO) << "F: " << d_F; + DLOG(INFO) << "H: " << d_H; + DLOG(INFO) << "R: " << d_R; + DLOG(INFO) << "Q: " << d_Q; + DLOG(INFO) << "P: " << d_P_old_old; + DLOG(INFO) << "x: " << d_x_old_old; +} + +void Pvt_Kf::run_Kf(arma::vec p, arma::vec v) +{ + // + // Pkp{1,i}=F*Pk{1,i-1}*F'+Q; + // Xkp{1,i}=F*Xk{1,i-1}; %nuevo estado a partir del modelo de transición + // + // %% Ganancia de Kalman + // + // K=Pkp{1,i}*A'*inv(A*Pkp{1,i}*A'+R); %en base a lo que acaba de predecir + // + // %% Corrección de la predicción y la covarianza, usando la info de las + // %% observaciones + // + // Xk{1,i}=Xkp{1,i}+K*(Z{1,i}-A*Xkp{1,i}); %correccion de lo predicho en base a la observación Z + // + // Pk{1,i}=(eye(4)-K*A)*Pkp{1,i}; % Corrección de la covarianza + // %pause(1) + // + + // Kalman loop + // Prediction + // std::cout << "d_x_old_old=" << d_x_old_old << "\n"; + d_x_new_old = d_F * d_x_old_old; + // std::cout << "d_x_new_old=" << d_x_new_old << "\n"; + d_P_new_old = d_F * d_P_old_old * d_F.t() + d_Q; + + // Measurement update + arma::vec z = arma::join_cols(p, v); + arma::mat K = d_P_new_old * d_H.t() * arma::inv(d_H * d_P_new_old * d_H.t() + d_R); // Kalman gain + d_x_new_new = d_x_new_old + K * (z - d_H * d_x_new_old); + // std::cout << "z=" << z << "\n"; + // std::cout << "K=" << K << "\n"; + + // std::cout << "d_x_new_new=" << d_x_new_new << "\n"; + d_P_new_new = (arma::eye(6, 6) - K * d_H) * d_P_new_old; + + // prepare data for next KF epoch + d_x_old_old = d_x_new_new; + d_P_old_old = d_P_new_new; +} + +Pvt_Kf::Pvt_Kf() +{ + initialized = false; +} + +void Pvt_Kf::get_pvt(arma::vec& p, arma::vec& v) +{ + p = d_x_new_new.subvec(0, 2); + v = d_x_new_new.subvec(3, 5); +} diff --git a/src/algorithms/PVT/libs/pvt_kf.h b/src/algorithms/PVT/libs/pvt_kf.h new file mode 100644 index 000000000..ce1a3f8ba --- /dev/null +++ b/src/algorithms/PVT/libs/pvt_kf.h @@ -0,0 +1,66 @@ +/*! + * \file Pvt_Kf.h + * \brief Kalman Filter for Position and Velocity + * \author Javier Arribas, 2023. jarribas(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PVT_KF_H +#define GNSS_SDR_PVT_KF_H + +#include + +/** \addtogroup PVT + * \{ */ +/** \addtogroup PVT_libs + * \{ */ + + +/*! + * \brief Kalman Filter for Position and Velocity + * + */ +class Pvt_Kf +{ +public: + Pvt_Kf(); + virtual ~Pvt_Kf() = default; + void init_kf(arma::vec p, arma::vec v, + double solver_interval_s, + double measures_ecef_pos_sd_m, + double measures_ecef_vel_sd_ms, + double system_ecef_pos_sd_m, + double system_ecef_vel_sd_ms); + + void run_Kf(arma::vec p, arma::vec v); + bool initialized; + void get_pvt(arma::vec &p, arma::vec &v); + +private: + // Kalman Filter class variables + arma::mat d_F; + arma::mat d_H; + arma::mat d_R; + arma::mat d_Q; + arma::mat d_P_old_old; + arma::mat d_P_new_old; + arma::mat d_P_new_new; + arma::vec d_x_old_old; + arma::vec d_x_new_old; + arma::vec d_x_new_new; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_Pvt_Kf_H diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index 8763cc12a..538de50df 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -49,12 +49,13 @@ Rtklib_Solver::Rtklib_Solver(const rtk_t &rtk, uint32_t type_of_rx, bool flag_dump_to_file, bool flag_dump_to_mat, - bool use_e6_for_pvt) : d_dump_filename(dump_filename), - d_rtk(rtk), - d_type_of_rx(type_of_rx), - d_flag_dump_enabled(flag_dump_to_file), - d_flag_dump_mat_enabled(flag_dump_to_mat), - d_use_e6_for_pvt(use_e6_for_pvt) + Pvt_Conf conf) : d_dump_filename(dump_filename), + d_rtk(rtk), + d_type_of_rx(type_of_rx), + d_flag_dump_enabled(flag_dump_to_file), + d_flag_dump_mat_enabled(flag_dump_to_mat), + d_conf(conf) + { this->set_averaging_flag(false); @@ -1039,7 +1040,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; } } - if (sig_ == "E6" && d_use_e6_for_pvt) + if (sig_ == "E6" && d_conf.use_e6_for_pvt) { galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) @@ -1466,6 +1467,10 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ d_rtk.neb = 0; // clear error buffer to avoid repeating the error message this->set_time_offset_s(0.0); // reset rx time estimation this->set_num_valid_observations(0); + if (d_conf.enable_pvt_kf == true) + { + d_pvt_kf.initialized = false; + } } else { @@ -1500,9 +1505,41 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ } this->set_valid_position(true); std::array rx_position_and_time{}; + + if (d_conf.enable_pvt_kf == true) + { + if (d_pvt_kf.initialized == false) + { + arma::vec p = {pvt_sol.rr[0], pvt_sol.rr[1], pvt_sol.rr[2]}; + arma::vec v = {pvt_sol.rr[3], pvt_sol.rr[4], pvt_sol.rr[5]}; + + d_pvt_kf.init_kf(p, + v, + d_conf.observable_interval_ms / 1000.0, + d_conf.measures_ecef_pos_sd_m, + d_conf.measures_ecef_vel_sd_ms, + d_conf.system_ecef_pos_sd_m, + d_conf.system_ecef_vel_sd_ms); + } + else + { + arma::vec p = {pvt_sol.rr[0], pvt_sol.rr[1], pvt_sol.rr[2]}; + arma::vec v = {pvt_sol.rr[3], pvt_sol.rr[4], pvt_sol.rr[5]}; + d_pvt_kf.run_Kf(p, v); + d_pvt_kf.get_pvt(p, v); + pvt_sol.rr[0] = p[0]; // [m] + pvt_sol.rr[1] = p[1]; // [m] + pvt_sol.rr[2] = p[2]; // [m] + pvt_sol.rr[3] = v[0]; // [ms] + pvt_sol.rr[4] = v[1]; // [ms] + pvt_sol.rr[5] = v[2]; // [ms] + } + } + rx_position_and_time[0] = pvt_sol.rr[0]; // [m] rx_position_and_time[1] = pvt_sol.rr[1]; // [m] rx_position_and_time[2] = pvt_sol.rr[2]; // [m] + // todo: fix this ambiguity in the RTKLIB units in receiver clock offset! if (d_rtk.opt.mode == PMODE_SINGLE) { diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h index 0a7fc056b..b967cb02f 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.h +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -56,6 +56,8 @@ #include "gps_iono.h" #include "gps_utc_model.h" #include "monitor_pvt.h" +#include "pvt_conf.h" +#include "pvt_kf.h" #include "pvt_solution.h" #include "rtklib.h" #include "rtklib_conversions.h" @@ -84,7 +86,7 @@ public: uint32_t type_of_rx, bool flag_dump_to_file, bool flag_dump_to_mat, - bool use_e6_for_pvt = true); + Pvt_Conf conf); ~Rtklib_Solver(); bool get_PVT(const std::map& gnss_observables_map, bool flag_averaging); @@ -152,7 +154,8 @@ private: uint32_t d_type_of_rx; bool d_flag_dump_enabled; bool d_flag_dump_mat_enabled; - bool d_use_e6_for_pvt; + Pvt_Conf d_conf; + Pvt_Kf d_pvt_kf; }; diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc index 94c904f95..fcc0920be 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc @@ -17,6 +17,7 @@ #include "gnss_sdr_filesystem.h" #include "nmea_printer.h" +#include "pvt_conf.h" #include "rtklib_rtkpos.h" #include "rtklib_solver.h" #include @@ -144,7 +145,9 @@ void NmeaPrinterTest::conf() TEST_F(NmeaPrinterTest, PrintLine) { std::string filename("nmea_test.nmea"); - std::shared_ptr pvt_solution = std::make_shared(rtk, "filename", 1, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + std::shared_ptr pvt_solution = std::make_shared(rtk, "filename", 1, false, false, conf); boost::posix_time::ptime pt(boost::gregorian::date(1994, boost::date_time::Nov, 19), boost::posix_time::hours(22) + boost::posix_time::minutes(54) + boost::posix_time::seconds(46)); diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc index 05f7d115e..a4a4fe90a 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc @@ -15,6 +15,7 @@ */ #include "gnss_sdr_filesystem.h" +#include "pvt_conf.h" #include "rinex_printer.h" #include "rtklib_rtkpos.h" #include "rtklib_solver.h" @@ -142,7 +143,9 @@ void RinexPrinterTest::conf() TEST_F(RinexPrinterTest, GalileoObsHeader) { - auto pvt_solution = std::make_shared(rtk, "filename", 4, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 4, false, false, conf); auto eph = Galileo_Ephemeris(); eph.PRN = 1; pvt_solution->galileo_ephemeris_map[1] = eph; @@ -228,7 +231,9 @@ TEST_F(RinexPrinterTest, GalileoObsHeader) TEST_F(RinexPrinterTest, GlonassObsHeader) { - auto pvt_solution = std::make_shared(rtk, "filename", 28, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 28, false, false, conf); auto eph = Glonass_Gnav_Ephemeris(); eph.PRN = 1; pvt_solution->glonass_gnav_ephemeris_map[1] = eph; @@ -288,7 +293,9 @@ TEST_F(RinexPrinterTest, MixedObsHeader) auto eph_gps = Gps_Ephemeris(); eph_gal.PRN = 1; eph_gps.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 106, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 106, false, false, conf); pvt_solution->galileo_ephemeris_map[1] = eph_gal; pvt_solution->gps_ephemeris_map[1] = eph_gps; @@ -358,7 +365,9 @@ TEST_F(RinexPrinterTest, MixedObsHeaderGpsGlo) auto eph_gps = Gps_Ephemeris(); eph_glo.PRN = 1; eph_gps.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 26, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 26, false, false, conf); pvt_solution->glonass_gnav_ephemeris_map[1] = eph_glo; pvt_solution->gps_ephemeris_map[1] = eph_gps; @@ -425,7 +434,9 @@ TEST_F(RinexPrinterTest, GalileoObsLog) bool no_more_finds = false; auto eph = Galileo_Ephemeris(); eph.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 4, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 4, false, false, conf); pvt_solution->galileo_ephemeris_map[1] = eph; std::map gnss_observables_map; @@ -505,7 +516,9 @@ TEST_F(RinexPrinterTest, GlonassObsLog) bool no_more_finds = false; auto eph = Glonass_Gnav_Ephemeris(); eph.PRN = 22; - auto pvt_solution = std::make_shared(rtk, "filename", 23, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 23, false, false, conf); pvt_solution->glonass_gnav_ephemeris_map[1] = eph; std::map gnss_observables_map; @@ -587,7 +600,9 @@ TEST_F(RinexPrinterTest, GpsObsLogDualBand) auto eph_cnav = Gps_CNAV_Ephemeris(); eph.PRN = 1; eph_cnav.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 7, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 7, false, false, conf); pvt_solution->gps_ephemeris_map[1] = eph; pvt_solution->gps_cnav_ephemeris_map[1] = eph_cnav; std::map gnss_observables_map; @@ -675,7 +690,9 @@ TEST_F(RinexPrinterTest, GpsObsLogDualBand) TEST_F(RinexPrinterTest, GalileoObsLogDualBand) { - auto pvt_solution = std::make_shared(rtk, "filename", 14, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 14, false, false, conf); auto eph = Galileo_Ephemeris(); eph.PRN = 1; pvt_solution->galileo_ephemeris_map[1] = eph; @@ -775,7 +792,9 @@ TEST_F(RinexPrinterTest, MixedObsLog) auto eph_gal = Galileo_Ephemeris(); eph_gps.PRN = 1; eph_gal.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 9, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 9, false, false, conf); pvt_solution->gps_ephemeris_map[1] = eph_gps; pvt_solution->galileo_ephemeris_map[1] = eph_gal; std::map gnss_observables_map; @@ -899,7 +918,9 @@ TEST_F(RinexPrinterTest, MixedObsLogGpsGlo) auto eph_glo = Glonass_Gnav_Ephemeris(); eph_gps.PRN = 1; eph_glo.PRN = 1; - auto pvt_solution = std::make_shared(rtk, "filename", 26, false, false); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto pvt_solution = std::make_shared(rtk, "filename", 26, false, false, conf); pvt_solution->gps_ephemeris_map[1] = eph_gps; pvt_solution->glonass_gnav_ephemeris_map[1] = eph_glo; std::map gnss_observables_map; diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc index 4da572895..805ffdb9e 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc @@ -18,6 +18,7 @@ #include "gnss_sdr_make_unique.h" #include "gnss_sdr_supl_client.h" #include "in_memory_configuration.h" +#include "pvt_conf.h" #include "rtklib_solver.h" #include #include @@ -28,7 +29,6 @@ #include #include - rtk_t configure_rtklib_options() { std::shared_ptr configuration; @@ -384,7 +384,9 @@ TEST(RTKLibSolverTest, test1) bool save_to_mat = false; rtk_t rtk = configure_rtklib_options(); - auto d_ls_pvt = std::make_unique(rtk, nchannels, dump_filename, 1, flag_dump_to_file, save_to_mat); + Pvt_Conf conf; + conf.use_e6_for_pvt = false; + auto d_ls_pvt = std::make_unique(rtk, nchannels, dump_filename, 1, flag_dump_to_file, save_to_mat, conf); d_ls_pvt->set_averaging_depth(1); // load ephemeris From 4c448251fae7a361ca31426a529ed71181383486 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 4 Jul 2023 17:19:17 +0200 Subject: [PATCH 23/31] Code cleaning --- src/algorithms/PVT/libs/pvt_conf.h | 2 +- src/algorithms/PVT/libs/pvt_kf.cc | 26 ++------------------------ 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index 26aac201a..bf4a3501a 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -95,7 +95,7 @@ public: bool use_has_corrections = true; bool use_unhealthy_sats = false; - //PVT KF parameters + // PVT KF parameters bool enable_pvt_kf = false; double measures_ecef_pos_sd_m = 1.0; double measures_ecef_vel_sd_ms = 0.1; diff --git a/src/algorithms/PVT/libs/pvt_kf.cc b/src/algorithms/PVT/libs/pvt_kf.cc index be7871974..fc06b8757 100644 --- a/src/algorithms/PVT/libs/pvt_kf.cc +++ b/src/algorithms/PVT/libs/pvt_kf.cc @@ -38,7 +38,7 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, d_H = arma::eye(6, 6); - //measurement matrix static covariances + // measurement matrix static covariances d_R = {{pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, @@ -81,38 +81,16 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, void Pvt_Kf::run_Kf(arma::vec p, arma::vec v) { - // - // Pkp{1,i}=F*Pk{1,i-1}*F'+Q; - // Xkp{1,i}=F*Xk{1,i-1}; %nuevo estado a partir del modelo de transición - // - // %% Ganancia de Kalman - // - // K=Pkp{1,i}*A'*inv(A*Pkp{1,i}*A'+R); %en base a lo que acaba de predecir - // - // %% Corrección de la predicción y la covarianza, usando la info de las - // %% observaciones - // - // Xk{1,i}=Xkp{1,i}+K*(Z{1,i}-A*Xkp{1,i}); %correccion de lo predicho en base a la observación Z - // - // Pk{1,i}=(eye(4)-K*A)*Pkp{1,i}; % Corrección de la covarianza - // %pause(1) - // - // Kalman loop // Prediction - // std::cout << "d_x_old_old=" << d_x_old_old << "\n"; d_x_new_old = d_F * d_x_old_old; - // std::cout << "d_x_new_old=" << d_x_new_old << "\n"; d_P_new_old = d_F * d_P_old_old * d_F.t() + d_Q; // Measurement update arma::vec z = arma::join_cols(p, v); arma::mat K = d_P_new_old * d_H.t() * arma::inv(d_H * d_P_new_old * d_H.t() + d_R); // Kalman gain - d_x_new_new = d_x_new_old + K * (z - d_H * d_x_new_old); - // std::cout << "z=" << z << "\n"; - // std::cout << "K=" << K << "\n"; - // std::cout << "d_x_new_new=" << d_x_new_new << "\n"; + d_x_new_new = d_x_new_old + K * (z - d_H * d_x_new_old); d_P_new_new = (arma::eye(6, 6) - K * d_H) * d_P_new_old; // prepare data for next KF epoch From 1cf508ad200591f6b5543f5bb9b031deab47113d Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 4 Jul 2023 17:45:20 +0200 Subject: [PATCH 24/31] Code cleaning --- .../gnuradio_blocks/ad936x_iio_source.cc | 22 ++--- .../gr_complex_ip_packet_source.cc | 6 +- .../gr_complex_ip_packet_source.h | 2 +- .../signal_source/libs/ad936x_iio_custom.cc | 92 +++++++++---------- .../signal_source/libs/ad936x_iio_custom.h | 8 +- .../signal_source/libs/ad936x_iio_samples.h | 2 +- .../signal_source/libs/pps_samplestamp.h | 2 +- src/algorithms/signal_source/libs/ppstcprx.cc | 14 +-- 8 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index ffaae3e9c..45cc5046f 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -94,8 +94,8 @@ void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samp { for (ch = 0; ch < nchannels; ch++) { - //std::cout << current_byte << " of " << samples_in->n_bytes << " test: " << (int)samples_in->buffer[current_byte] << "\n"; - (*files_out).at(ch).write(&samples_in->buffer[current_byte], 4); //two bytes I + two bytes Q per channel + // std::cout << current_byte << " of " << samples_in->n_bytes << " test: " << (int)samples_in->buffer[current_byte] << "\n"; + (*files_out).at(ch).write(&samples_in->buffer[current_byte], 4); // two bytes I + two bytes Q per channel current_byte += 4; } } @@ -134,7 +134,7 @@ ad936x_iio_source::ad936x_iio_source( { if (ad936x_custom->initialize_device(pluto_uri_, board_type_) == true) { - //configure channels + // configure channels if (ad936x_custom->init_config_ad9361_rx(bandwidth_, sample_rate_, freq_, @@ -153,19 +153,19 @@ ad936x_iio_source::ad936x_iio_source( { std::cout << "ad936x_iio_source HW configured OK!\n"; - //PPS FPGA Samplestamp information from TCP server + // PPS FPGA Samplestamp information from TCP server pps_rx = std::make_shared(); ppsqueue = std::shared_ptr>(new Concurrent_Queue()); pps_rx->set_pps_samplestamp_queue(ppsqueue); ad936x_custom->set_pps_samplestamp_queue(ppsqueue); - //start PPS RX thread + // start PPS RX thread if (ppsmode_ == true or customsamplesize_ == true) { pps_rx_thread = std::thread(&pps_tcp_rx::receive_pps, pps_rx, fe_ip_, fe_ctlport_); std::this_thread::sleep_for(std::chrono::milliseconds(500)); - //configure custom FPGA options + // configure custom FPGA options switch (ssize_) { case 16: @@ -251,13 +251,13 @@ ad936x_iio_source::ad936x_iio_source( set_min_noutput_items(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2); // multiplexed I,Q, so, two samples per complex sample set_min_output_buffer(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * sizeof(int16_t) * 2); - //std::cout << "max_output_buffer " << min_output_buffer(0) << " min_noutput_items: " << min_noutput_items() << "\n"; + // std::cout << "max_output_buffer " << min_output_buffer(0) << " min_noutput_items: " << min_noutput_items() << "\n"; // for (int n = 0; n < ad936x_custom->n_channels; n++) // { // std::string cap_file_root_name = "./debug_cap_ch"; // samplesfile.push_back(std::fstream(cap_file_root_name + std::to_string(n) + ".dat", std::ios::out | std::ios::binary)); - // //samplesfile.back().exceptions(std::ios_base::badbit | std::ios_base::failbit); //this will enable exceptions for debug + // // samplesfile.back().exceptions(std::ios_base::badbit | std::ios_base::failbit); //this will enable exceptions for debug // // if (samplesfile.back().is_open() == false) // { @@ -301,7 +301,7 @@ int ad936x_iio_source::general_work(int noutput_items, ad936x_custom->pop_sample_buffer(current_buffer); current_samples = current_buffer.get(); - //I and Q samples are interleaved in buffer: IQIQIQ... + // I and Q samples are interleaved in buffer: IQIQIQ... int32_t n_interleaved_iq_samples_per_channel = current_samples->n_bytes / (ad936x_custom->n_channels * 2); if (noutput_items < n_interleaved_iq_samples_per_channel) { @@ -310,12 +310,12 @@ int ad936x_iio_source::general_work(int noutput_items, } else { - //ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile); + // ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile); uint32_t current_byte = 0; uint32_t current_byte_in_gr = 0; int16_t ch = 0; - //std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n"; + // std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n"; if (ad936x_custom->n_channels == 1) { memcpy(&((char *)output_items[0])[0], ¤t_samples->buffer[current_byte], current_samples->n_bytes); diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc index 20f829e6a..0153a11a2 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -193,7 +193,7 @@ bool Gr_Complex_Ip_Packet_Source::stop() bool Gr_Complex_Ip_Packet_Source::open() { std::array errbuf{}; - //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + // boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function gr::thread::scoped_lock guard(d_setlock); // open device for reading descr = pcap_open_live(d_src_device.c_str(), 1500, 1, 1000, errbuf.data()); @@ -250,7 +250,7 @@ void Gr_Complex_Ip_Packet_Source::static_pcap_callback(u_char *args, const struc void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char *args, __attribute__((unused)) const struct pcap_pkthdr *pkthdr, const u_char *packet) { - //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + // boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function const gr_ip_header *ih; const gr_udp_header *uh; @@ -500,7 +500,7 @@ int Gr_Complex_Ip_Packet_Source::work(int noutput_items, gr_vector_void_star &output_items) { // send samples to next GNU Radio block - //boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + // boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function if (fifo_items == 0) { return 0; diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h index 9f8939904..a7d37b5a0 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h @@ -83,7 +83,7 @@ private: bool open(); boost::thread *d_pcap_thread; - //boost::mutex d_mutex; + // boost::mutex d_mutex; struct sockaddr_in si_me { }; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index efd67e778..c9d788bdd 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -40,10 +40,10 @@ ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_) ad936x_iio_custom::~ad936x_iio_custom() { - //disable TX + // disable TX if (phy != NULL) PlutoTxEnable(false); - //Close device + // Close device if (ctx != NULL) iio_context_destroy(ctx); } @@ -60,7 +60,7 @@ void ad936x_iio_custom::set_pps_samplestamp_queue(std::shared_ptr(&pps.samplestamp), sizeof(uint64_t)); - //int32_t: Galileo/GPS Week Number associated to the rising edge of PPS signal + // int32_t: Galileo/GPS Week Number associated to the rising edge of PPS signal // ppstimefile.write(reinterpret_cast(&tow.week), sizeof(int32_t)); - //int32_t: Galileo/GPS TOW associated to the rising edge of PPS signal + // int32_t: Galileo/GPS TOW associated to the rising edge of PPS signal // ppstimefile.write(reinterpret_cast(&tow.tow_ms), sizeof(int32_t)); - //record pps rise samplestamp associated to the absolute sample counter - //PPS rising edge must be associated with the corresponding uBlox time message (tx once a second) + // record pps rise samplestamp associated to the absolute sample counter + // PPS rising edge must be associated with the corresponding uBlox time message (tx once a second) if (GnssTime_queue->timed_wait_and_pop(tow, 2000) == false) @@ -1066,10 +1066,10 @@ void ad936x_iio_custom::get_PPS_timestamp() } bool ad936x_iio_custom::start_sample_rx(bool ppsmode) { - //using queues of smart pointers to preallocated buffers + // using queues of smart pointers to preallocated buffers free_buffers.clear(); used_buffers.clear(); - //preallocate buffers and use queues + // preallocate buffers and use queues std::cerr << "Allocating memory..\n"; try { @@ -1084,33 +1084,33 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode) return false; } - //prepare capture channels + // prepare capture channels std::vector channels; switch (n_channels) { case 1: - channels.push_back("voltage0"); //Channel 0 I - channels.push_back("voltage1"); //Channel 0 Q + channels.push_back("voltage0"); // Channel 0 I + channels.push_back("voltage1"); // Channel 0 Q break; case 2: - channels.push_back("voltage0"); //Channel 0 I - channels.push_back("voltage1"); //Channel 0 Q - channels.push_back("voltage2"); //Channel 1 I - channels.push_back("voltage3"); //Channel 1 Q + channels.push_back("voltage0"); // Channel 0 I + channels.push_back("voltage1"); // Channel 0 Q + channels.push_back("voltage2"); // Channel 1 I + channels.push_back("voltage3"); // Channel 1 Q break; default: - channels.push_back("voltage0"); //Channel 0 I - channels.push_back("voltage1"); //Channel 0 Q + channels.push_back("voltage0"); // Channel 0 I + channels.push_back("voltage1"); // Channel 0 Q } receive_samples = true; - //start sample capture thread + // start sample capture thread capture_samples_thread = std::thread(&ad936x_iio_custom::capture, this, channels); - //start sample overflow detector + // start sample overflow detector overflow_monitor_thread = std::thread(&ad936x_iio_custom::monitor_thread_fn, this); - //start PPS and GNSS Time capture thread + // start PPS and GNSS Time capture thread if (ppsmode == true) { diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.h b/src/algorithms/signal_source/libs/ad936x_iio_custom.h index de36f5b5b..83a61282a 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.h @@ -31,7 +31,7 @@ #endif #include "ad936x_iio_samples.h" -#include //multichip sync and high level functions +#include // multichip sync and high level functions #include #include @@ -114,13 +114,13 @@ private: void PlutoTxEnable(bool txon); void setPlutoGpo(int p); - //Device structure + // Device structure struct iio_context *ctx; struct iio_device *phy; struct iio_device *stream_dev; struct iio_device *dds_dev; - //stream + // stream uint64_t sample_rate_sps; @@ -135,7 +135,7 @@ private: boost::atomic receive_samples; boost::atomic fpga_overflow; - //using queues of smart pointers to preallocated buffers + // using queues of smart pointers to preallocated buffers Concurrent_Queue> free_buffers; Concurrent_Queue> used_buffers; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_samples.h b/src/algorithms/signal_source/libs/ad936x_iio_samples.h index 5156e89f0..96fd9e6ae 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_samples.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_samples.h @@ -34,7 +34,7 @@ public: uint32_t n_interleaved_iq_samples; uint16_t n_channels; uint16_t step_bytes; - char buffer[IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 4 * 4]; //max 16 bits samples per buffer (4 channels, 2-bytes per I + 2-bytes per Q) + char buffer[IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 4 * 4]; // max 16 bits samples per buffer (4 channels, 2-bytes per I + 2-bytes per Q) }; #endif diff --git a/src/algorithms/signal_source/libs/pps_samplestamp.h b/src/algorithms/signal_source/libs/pps_samplestamp.h index cdbc1276f..900388867 100644 --- a/src/algorithms/signal_source/libs/pps_samplestamp.h +++ b/src/algorithms/signal_source/libs/pps_samplestamp.h @@ -13,7 +13,7 @@ class PpsSamplestamp { public: - uint64_t samplestamp; //PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side + uint64_t samplestamp; // PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side uint32_t overflow_reg; // >0 indicates overflow situation in the FPGA RX buffer }; diff --git a/src/algorithms/signal_source/libs/ppstcprx.cc b/src/algorithms/signal_source/libs/ppstcprx.cc index 0a10d8545..73ea791db 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.cc +++ b/src/algorithms/signal_source/libs/ppstcprx.cc @@ -52,16 +52,16 @@ bool pps_tcp_rx::send_cmd(std::string cmd) } void pps_tcp_rx::receive_pps(std::string ip_address, int port) { - //create a message buffer + // create a message buffer char buf[1500]; - //setup a socket and connection tools + // setup a socket and connection tools sockaddr_in sendSockAddr; sendSockAddr.sin_family = AF_INET; sendSockAddr.sin_addr.s_addr = inet_addr(ip_address.c_str()); sendSockAddr.sin_port = htons(port); clientSd = socket(AF_INET, SOCK_STREAM, 0); - //try to connect... + // try to connect... int status = connect(clientSd, (sockaddr *)&sendSockAddr, sizeof(sendSockAddr)); if (status < 0) @@ -84,8 +84,8 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port) { if (new_pps_line.length() > 0) { - //std::cout << "pps_tcp_rx debug: " << new_pps_line << "\n"; - //parse string and push PPS data to the PPS queue + // std::cout << "pps_tcp_rx debug: " << new_pps_line << "\n"; + // parse string and push PPS data to the PPS queue std::stringstream ss(new_pps_line); std::vector data; while (ss.good()) @@ -97,7 +97,7 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port) if (data.size() >= 2) { PpsSamplestamp new_pps; - //sample counter + // sample counter std::size_t found = data.at(0).find("sc="); if (found != std::string::npos) { @@ -131,7 +131,7 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port) std::cout << "pps_tcp_rx debug: o parse error str " << data.at(1) << "\n"; } Pps_queue->push(new_pps); - //std::cout << "pps_tcp_rx debug: pps pushed!\n"; + // std::cout << "pps_tcp_rx debug: pps pushed!\n"; } else { From 1517bb1ab81c769a2d7c2bfb10c42f31b55c8c8d Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Wed, 5 Jul 2023 11:37:33 +0200 Subject: [PATCH 25/31] Make Clang-format happy --- .../signal_source/adapters/CMakeLists.txt | 1 - .../gnuradio_blocks/ad936x_iio_source.cc | 7 ++++--- .../gr_complex_ip_packet_source.cc | 2 +- .../signal_source/libs/ad936x_iio_custom.cc | 17 +++++++++-------- .../signal_source/libs/gnss_sdr_timestamp.h | 2 +- .../signal_source/libs/pps_samplestamp.h | 12 ++++++++++-- src/algorithms/signal_source/libs/ppstcprx.cc | 16 ++++++++++++---- src/algorithms/signal_source/libs/ppstcprx.h | 16 ++++++++++++---- 8 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 1fd3d6ee8..afbf36296 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -18,7 +18,6 @@ if(ENABLE_PLUTOSDR) ############################################## set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} plutosdr_signal_source.cc) set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} plutosdr_signal_source.h) - ############################################## # CUSTOM AD936X IIO SOURCE ############################################## diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index 45cc5046f..0cf885fe2 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -301,6 +301,7 @@ int ad936x_iio_source::general_work(int noutput_items, ad936x_custom->pop_sample_buffer(current_buffer); current_samples = current_buffer.get(); + // I and Q samples are interleaved in buffer: IQIQIQ... int32_t n_interleaved_iq_samples_per_channel = current_samples->n_bytes / (ad936x_custom->n_channels * 2); if (noutput_items < n_interleaved_iq_samples_per_channel) @@ -311,14 +312,14 @@ int ad936x_iio_source::general_work(int noutput_items, else { // ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile); - + auto **out = reinterpret_cast(&output_items[0]); uint32_t current_byte = 0; uint32_t current_byte_in_gr = 0; int16_t ch = 0; // std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n"; if (ad936x_custom->n_channels == 1) { - memcpy(&((char *)output_items[0])[0], ¤t_samples->buffer[current_byte], current_samples->n_bytes); + memcpy(out[0], ¤t_samples->buffer[current_byte], current_samples->n_bytes); } else { @@ -327,7 +328,7 @@ int ad936x_iio_source::general_work(int noutput_items, { for (ch = 0; ch < ad936x_custom->n_channels; ch++) { - memcpy(&((char *)output_items[ch])[current_byte_in_gr], ¤t_samples->buffer[current_byte], 4); // two bytes I + two bytes Q per channel: 4 bytes + memcpy(&out[ch][current_byte_in_gr], ¤t_samples->buffer[current_byte], 4); // two bytes I + two bytes Q per channel: 4 bytes current_byte += 4; } current_byte_in_gr += 4; diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc index 0153a11a2..04840a799 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -334,7 +334,7 @@ void Gr_Complex_Ip_Packet_Source::demux_samples(const gr_vector_void_star &outpu { if (d_wire_sample_type == 5) { - //interleaved 2-bit I 2-bit Q samples packed in bytes: 1 byte -> 2 complex samples + // interleaved 2-bit I 2-bit Q samples packed in bytes: 1 byte -> 2 complex samples int nsample = 0; byte_2bit_struct sample{}; // <- 2 bits wide only int real; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index c9d788bdd..1f7dfd823 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_) @@ -834,10 +835,10 @@ void ad936x_iio_custom::monitor_thread_fn() continue; } - // if (device_is_tx) { - // if (val & 1) - // fprintf(stderr, "Underflow detected\n"); - // } else { + // if (device_is_tx) { + // if (val & 1) + // fprintf(stderr, "Underflow detected\n"); + // } else { if (val & 4) { std::cout << "WARNING: IIO status register reported overflow!\n"; @@ -909,7 +910,7 @@ void ad936x_iio_custom::PlutoTxEnable(bool txon) void ad936x_iio_custom::setPlutoGpo(int p) { char pins[11]; - sprintf(pins, "0x27 0x%x0", p); // direct access to AD9361 registers... WARNING! + snprintf(pins, sizeof(pins), "0x27 0x%x0", p); // direct access to AD9361 registers... WARNING! pins[9] = 0; int ret; // std::cout << "send: " << pins << " \n"; @@ -926,9 +927,9 @@ void ad936x_iio_custom::setPlutoGpo(int p) bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) { - // adi,gpo-manual-mode-enable Enables GPO manual mode, this will conflict with automatic ENSM slave and eLNA mode - // adi,gpo-manual-mode-enable-mask Enable bit mask, setting or clearing bits will change the level of the corresponding output. Bit0 → GPO, Bit1 → GPO1, Bit2 → GPO2, Bit3 → GP03 - // adi,gpo-manual-mode-enable + // adi,gpo-manual-mode-enable Enables GPO manual mode, this will conflict with automatic ENSM slave and eLNA mode + // adi,gpo-manual-mode-enable-mask Enable bit mask, setting or clearing bits will change the level of the corresponding output. Bit0 → GPO, Bit1 → GPO1, Bit2 → GPO2, Bit3 → GP03 + // adi,gpo-manual-mode-enable // adi,gpo-manual-mode-enable-mask does not work... // some software use the direct_reg_access (see https://github.com/g4eml/Langstone/blob/master/LangstoneGUI.c) diff --git a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h index 11716ca82..6caafd8e5 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h +++ b/src/algorithms/signal_source/libs/gnss_sdr_timestamp.h @@ -71,8 +71,8 @@ private: double d_clock_offset_ms; double d_fraction_ms_offset; double d_integer_ms_offset; - uint64_t d_next_timetag_samplecount; int d_items_to_samples; + uint64_t d_next_timetag_samplecount; bool d_get_next_timetag; }; diff --git a/src/algorithms/signal_source/libs/pps_samplestamp.h b/src/algorithms/signal_source/libs/pps_samplestamp.h index 900388867..d6891aa3e 100644 --- a/src/algorithms/signal_source/libs/pps_samplestamp.h +++ b/src/algorithms/signal_source/libs/pps_samplestamp.h @@ -1,8 +1,16 @@ -/* ------------------------------------------------------------------------- +/*! + * \file pps_samplestamp.h + * \brief A simple container for the sample count associated to PPS rising edge + * \author Javier Arribas, jarribas(at)cttc.es + * ----------------------------------------------------------------------------- * - * Copyright (C) 2022 (see AUTHORS file for a list of contributors) + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later * + * ----------------------------------------------------------------------------- */ #ifndef IIOPPS_PPS_SAMPLESTAMP_H diff --git a/src/algorithms/signal_source/libs/ppstcprx.cc b/src/algorithms/signal_source/libs/ppstcprx.cc index 73ea791db..93db26f61 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.cc +++ b/src/algorithms/signal_source/libs/ppstcprx.cc @@ -1,8 +1,16 @@ -/* - * ppstcprx.cc +/*! + * \file ppstcprx.cc + * \brief TCP client class for front-end PPS samplestamp information reception + * \author Javier Arribas, jarribas(at)cttc.es + * ----------------------------------------------------------------------------- * - * Created on: 28 feb 2022 - * Author: javier + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- */ #include "ppstcprx.h" diff --git a/src/algorithms/signal_source/libs/ppstcprx.h b/src/algorithms/signal_source/libs/ppstcprx.h index 37c8de92f..653b2fdbd 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.h +++ b/src/algorithms/signal_source/libs/ppstcprx.h @@ -1,8 +1,16 @@ -/* - * ppstcprx.h +/*! + * \file ppstcprx.h + * \brief TCP client class for front-end PPS samplestamp information reception + * \author Javier Arribas, jarribas(at)cttc.es + * ----------------------------------------------------------------------------- * - * Created on: 28 feb 2022 - * Author: javier + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- */ #ifndef SRC_LIBS_PPSTCPRX_H_ From 8e42b55f8d2fbc696ca77166cff17288552039f3 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Wed, 5 Jul 2023 12:02:50 +0200 Subject: [PATCH 26/31] Code cleaning --- src/algorithms/signal_source/libs/ad936x_iio_custom.cc | 2 +- src/algorithms/signal_source/libs/pps_samplestamp.h | 4 ++-- src/algorithms/signal_source/libs/ppstcprx.cc | 1 + src/algorithms/signal_source/libs/ppstcprx.h | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 1f7dfd823..c99dba789 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -947,7 +947,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) if (check_device() == false) return false; - int plutoGpo = 0; + // int plutoGpo = 0; int ret; ret = iio_device_debug_attr_write(phy, "adi,gpo-manual-mode-enable", "1"); diff --git a/src/algorithms/signal_source/libs/pps_samplestamp.h b/src/algorithms/signal_source/libs/pps_samplestamp.h index d6891aa3e..df4b40929 100644 --- a/src/algorithms/signal_source/libs/pps_samplestamp.h +++ b/src/algorithms/signal_source/libs/pps_samplestamp.h @@ -21,8 +21,8 @@ class PpsSamplestamp { public: - uint64_t samplestamp; // PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side - uint32_t overflow_reg; // >0 indicates overflow situation in the FPGA RX buffer + uint64_t samplestamp = 0; // PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side + uint32_t overflow_reg = 0; // >0 indicates overflow situation in the FPGA RX buffer }; #endif diff --git a/src/algorithms/signal_source/libs/ppstcprx.cc b/src/algorithms/signal_source/libs/ppstcprx.cc index 93db26f61..0855ad0b6 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.cc +++ b/src/algorithms/signal_source/libs/ppstcprx.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include pps_tcp_rx::pps_tcp_rx() diff --git a/src/algorithms/signal_source/libs/ppstcprx.h b/src/algorithms/signal_source/libs/ppstcprx.h index 653b2fdbd..3fb5878fb 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.h +++ b/src/algorithms/signal_source/libs/ppstcprx.h @@ -18,10 +18,12 @@ #include "concurrent_queue.h" #include "pps_samplestamp.h" #include +#include #include #include #include #include + class pps_tcp_rx { private: From 4f9a9068e97041550f34e6160e7b8643659cc01c Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Wed, 5 Jul 2023 15:51:01 +0200 Subject: [PATCH 27/31] Bug fix in iio signal source and ip packet source --- .../gnuradio_blocks/gr_complex_ip_packet_source.cc | 5 ++++- src/algorithms/signal_source/libs/ad936x_iio_custom.cc | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc index 04840a799..d5659d0dc 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -19,6 +19,7 @@ #include "gr_complex_ip_packet_source.h" #include +#include #include #include #include @@ -110,7 +111,7 @@ Gr_Complex_Ip_Packet_Source::Gr_Complex_Ip_Packet_Source(std::string src_device, d_pcap_thread(nullptr), d_src_device(std::move(src_device)), descr(nullptr), - fifo_buff(new char[FIFO_SIZE]), + fifo_buff(static_cast(volk_malloc(static_cast(FIFO_SIZE * sizeof(char)), volk_get_alignment()))), fifo_read_ptr(0), fifo_write_ptr(0), fifo_items(0), @@ -297,6 +298,7 @@ void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char * if (aligned_write_items >= payload_length_bytes) { // write all in a single memcpy + gr::thread::scoped_lock guard(d_setlock); memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], payload_length_bytes); // size in bytes fifo_write_ptr += payload_length_bytes; if (fifo_write_ptr == FIFO_SIZE) @@ -308,6 +310,7 @@ void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char * else { // two step wrap write + gr::thread::scoped_lock guard(d_setlock); memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], aligned_write_items); // size in bytes fifo_write_ptr = payload_length_bytes - aligned_write_items; memcpy(&fifo_buff[0], &udp_payload[aligned_write_items], fifo_write_ptr); // size in bytes diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index c99dba789..e487d29b5 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -581,9 +581,11 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, // { // std::cout << "Warning: Unable to set AD936x RX filter parameters!\n"; // } + n_channels = 0; if (enable_ch0 == true) { - std::cerr << "* Get AD9361 Phy RX channel 0...\n"; + n_channels++; + std::cout << "* Get AD9361 Phy RX channel 0...\n"; std::stringstream name; name.str(""); name << "voltage"; @@ -634,7 +636,8 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, if (enable_ch1 == true) { - std::cerr << "* Get AD9361 Phy RX channel 1...\n"; + n_channels++; + std::cout << "* Get AD9361 Phy RX channel 1...\n"; std::stringstream name; name.str(""); name << "voltage"; From a29f52e2e48b184e10d0cf3d5bc5f781f05a2980 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 5 Jul 2023 19:37:35 +0200 Subject: [PATCH 28/31] Make clang-tidy happy --- src/algorithms/PVT/libs/pvt_kf.cc | 21 ++++++++---------- src/algorithms/PVT/libs/pvt_kf.h | 14 ++++++------ src/algorithms/PVT/libs/rtklib_solver.cc | 5 ++--- src/algorithms/PVT/libs/rtklib_solver.h | 4 ++-- .../adapters/file_timestamp_signal_source.cc | 22 ++++++++++++------- .../adapters/file_timestamp_signal_source.h | 3 ++- 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/algorithms/PVT/libs/pvt_kf.cc b/src/algorithms/PVT/libs/pvt_kf.cc index fc06b8757..a0fdda1d3 100644 --- a/src/algorithms/PVT/libs/pvt_kf.cc +++ b/src/algorithms/PVT/libs/pvt_kf.cc @@ -1,5 +1,5 @@ /*! - * \file Pvt_Kf.cc + * \file pvt_kf.cc * \brief Kalman Filter for Position and Velocity * \author Javier Arribas, 2023. jarribas(at)cttc.es * @@ -14,11 +14,13 @@ * * ----------------------------------------------------------------------------- */ + #include "pvt_kf.h" #include -void Pvt_Kf::init_kf(arma::vec p, arma::vec v, +void Pvt_Kf::init_kf(const arma::vec& p, + const arma::vec& v, double solver_interval_s, double measures_ecef_pos_sd_m, double measures_ecef_vel_sd_ms, @@ -28,7 +30,6 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, // Kalman Filter class variables const double Ti = solver_interval_s; - std::cout << "Ti=" << Ti << "\n"; d_F = {{1.0, 0.0, 0.0, Ti, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0, Ti, 0.0}, {0.0, 0.0, 1.0, 0.0, 0.0, Ti}, @@ -38,7 +39,7 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, d_H = arma::eye(6, 6); - // measurement matrix static covariances + // measurement matrix static covariances d_R = {{pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, @@ -46,9 +47,7 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, {0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0), 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0)}}; - // system covariance matrix (static) - d_Q = {{pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0}, @@ -71,6 +70,7 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, initialized = true; + DLOG(INFO) << "Ti: " << Ti; DLOG(INFO) << "F: " << d_F; DLOG(INFO) << "H: " << d_H; DLOG(INFO) << "R: " << d_R; @@ -79,9 +79,10 @@ void Pvt_Kf::init_kf(arma::vec p, arma::vec v, DLOG(INFO) << "x: " << d_x_old_old; } -void Pvt_Kf::run_Kf(arma::vec p, arma::vec v) + +void Pvt_Kf::run_Kf(const arma::vec& p, const arma::vec& v); { - // Kalman loop + // Kalman loop // Prediction d_x_new_old = d_F * d_x_old_old; d_P_new_old = d_F * d_P_old_old * d_F.t() + d_Q; @@ -98,10 +99,6 @@ void Pvt_Kf::run_Kf(arma::vec p, arma::vec v) d_P_old_old = d_P_new_new; } -Pvt_Kf::Pvt_Kf() -{ - initialized = false; -} void Pvt_Kf::get_pvt(arma::vec& p, arma::vec& v) { diff --git a/src/algorithms/PVT/libs/pvt_kf.h b/src/algorithms/PVT/libs/pvt_kf.h index ce1a3f8ba..26dc25a43 100644 --- a/src/algorithms/PVT/libs/pvt_kf.h +++ b/src/algorithms/PVT/libs/pvt_kf.h @@ -1,5 +1,5 @@ /*! - * \file Pvt_Kf.h + * \file pvt_kf.h * \brief Kalman Filter for Position and Velocity * \author Javier Arribas, 2023. jarribas(at)cttc.es * @@ -33,18 +33,18 @@ class Pvt_Kf { public: - Pvt_Kf(); + Pvt_Kf() = default; virtual ~Pvt_Kf() = default; - void init_kf(arma::vec p, arma::vec v, + void init_kf(const arma::vec& p, + const arma::vec& v, double solver_interval_s, double measures_ecef_pos_sd_m, double measures_ecef_vel_sd_ms, double system_ecef_pos_sd_m, double system_ecef_vel_sd_ms); - - void run_Kf(arma::vec p, arma::vec v); - bool initialized; - void get_pvt(arma::vec &p, arma::vec &v); + void run_Kf(const arma::vec& p, const arma::vec& v); + void get_pvt(arma::vec& p, arma::vec& v); + bool initialized{false}; private: // Kalman Filter class variables diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index 70384d613..e17edfa14 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -51,11 +51,10 @@ Rtklib_Solver::Rtklib_Solver(const rtk_t &rtk, bool flag_dump_to_mat, Pvt_Conf conf) : d_dump_filename(dump_filename), d_rtk(rtk), + d_conf(std::move(conf)), d_type_of_rx(type_of_rx), d_flag_dump_enabled(flag_dump_to_file), - d_flag_dump_mat_enabled(flag_dump_to_mat), - d_conf(conf) - + d_flag_dump_mat_enabled(flag_dump_to_mat) { this->set_averaging_flag(false); diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h index b967cb02f..7bffa042d 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.h +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -151,11 +151,11 @@ private: rtk_t d_rtk{}; nav_t d_nav_data{}; Monitor_Pvt d_monitor_pvt{}; + Pvt_Conf d_conf; + Pvt_Kf d_pvt_kf; uint32_t d_type_of_rx; bool d_flag_dump_enabled; bool d_flag_dump_mat_enabled; - Pvt_Conf d_conf; - Pvt_Kf d_pvt_kf; }; diff --git a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc index 8e17180f8..8a7c2958f 100644 --- a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.cc @@ -1,6 +1,7 @@ /*! - * \file file_timestamp_signal_source.h - * \brief This class reads samples stored in a file and generate stream tags with its timestamp information stored in separated file + * \file file_timestamp_signal_source.cc + * \brief This class reads samples stored in a file and generate stream tags + * with its timestamp information stored in separated file * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- @@ -13,6 +14,7 @@ * * ----------------------------------------------------------------------------- */ + #include "file_timestamp_signal_source.h" #include "gnss_sdr_flags.h" #include "gnss_sdr_string_literals.h" @@ -22,7 +24,9 @@ using namespace std::string_literals; FileTimestampSignalSource::FileTimestampSignalSource(const ConfigurationInterface* configuration, - const std::string& role, unsigned int in_streams, unsigned int out_streams, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, Concurrent_Queue* queue) : FileSourceBase(configuration, role, "File_Timestamp_Signal_Source"s, queue, "byte"s), timestamp_file_(configuration->property(role + ".timestamp_filename"s, "../data/example_capture_timestamp.dat"s)), @@ -53,23 +57,23 @@ void FileTimestampSignalSource::create_file_source_hook() int source_items_to_samples = 1; bool is_complex = false; - if (item_type().compare("ibyte") == 0) + if (item_type() == "ibyte") { source_items_to_samples = 1; } - else if (item_type().compare("byte") == 0) + else if (item_type() == "byte") { source_items_to_samples = 1; } - else if (item_type().compare("short") == 0) + else if (item_type() == "short") { source_items_to_samples = 1; } - else if (item_type().compare("ishort") == 0) + else if (item_type() == "ishort") { source_items_to_samples = 1; } - else if (item_type().compare("gr_complex") == 0) + else if (item_type() == "gr_complex") { source_items_to_samples = 1; is_complex = true; @@ -96,12 +100,14 @@ void FileTimestampSignalSource::create_file_source_hook() DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")"; } + void FileTimestampSignalSource::pre_connect_hook(gr::top_block_sptr top_block) { top_block->connect(file_source(), 0, timestamp_block_, 0); DLOG(INFO) << "connected file_source to timestamp_block_"; } + void FileTimestampSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block) { top_block->disconnect(file_source(), 0, timestamp_block_, 0); diff --git a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.h b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.h index f95b3622e..0c82cab86 100644 --- a/src/algorithms/signal_source/adapters/file_timestamp_signal_source.h +++ b/src/algorithms/signal_source/adapters/file_timestamp_signal_source.h @@ -1,6 +1,7 @@ /*! * \file file_timestamp_signal_source.h - * \brief This class reads samples stored in a file and generate stream tags with its timestamp information stored in separated file + * \brief This class reads samples stored in a file and generate stream tags + * with its timestamp information stored in separated file * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- From 5759e0a38545abeaaae3a033c044affa9f6bdda7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 5 Jul 2023 19:39:17 +0200 Subject: [PATCH 29/31] Bump Benchmark to 1.8.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 398c1f266..23e562631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,7 +344,7 @@ set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.13") set(GNSSSDR_GTEST_LOCAL_VERSION "1.13.0") set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master") set(GNSSSDR_GNSSTK_LOCAL_VERSION "14.0.0") -set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.0") +set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.1") set(GNSSSDR_MATHJAX_EXTERNAL_VERSION "2.7.7") # Downgrade versions if requirements are not met From 4cc4a6cbb62e678acf2d6089ee12921e80777b6c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 5 Jul 2023 20:03:22 +0200 Subject: [PATCH 30/31] Update changelog --- docs/CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5fd567b0c..422237dd3 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,20 @@ SPDX-FileCopyrightText: 2011-2023 Carles Fernandez-Prades Date: Wed, 5 Jul 2023 20:20:51 +0200 Subject: [PATCH 31/31] Add missing change --- src/algorithms/PVT/libs/pvt_kf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/PVT/libs/pvt_kf.cc b/src/algorithms/PVT/libs/pvt_kf.cc index a0fdda1d3..10083b221 100644 --- a/src/algorithms/PVT/libs/pvt_kf.cc +++ b/src/algorithms/PVT/libs/pvt_kf.cc @@ -80,7 +80,7 @@ void Pvt_Kf::init_kf(const arma::vec& p, } -void Pvt_Kf::run_Kf(const arma::vec& p, const arma::vec& v); +void Pvt_Kf::run_Kf(const arma::vec& p, const arma::vec& v) { // Kalman loop // Prediction