From 1313edd7162ad465554d9018d2f3962698887ccc Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Tue, 16 Jul 2019 17:41:12 +0200 Subject: [PATCH] Partial implementation of the new event queue and its dependencies. Still NOT usable --- src/algorithms/PVT/libs/rtcm.h | 1 + .../channel/adapters/CMakeLists.txt | 1 + src/algorithms/channel/adapters/channel.cc | 2 +- src/algorithms/channel/adapters/channel.h | 7 +- src/algorithms/channel/libs/CMakeLists.txt | 1 + src/algorithms/channel/libs/channel_fsm.cc | 22 +- src/algorithms/channel/libs/channel_fsm.h | 7 +- src/algorithms/libs/pass_through.cc | 6 + .../signal_generator/adapters/CMakeLists.txt | 1 + .../adapters/signal_generator.cc | 2 +- .../adapters/signal_generator.h | 7 +- .../adapters/ad9361_fpga_signal_source.cc | 2 +- .../adapters/ad9361_fpga_signal_source.h | 7 +- .../adapters/custom_udp_signal_source.cc | 2 +- .../adapters/custom_udp_signal_source.h | 7 +- .../adapters/file_signal_source.cc | 2 +- .../adapters/file_signal_source.h | 8 +- .../adapters/flexiband_signal_source.cc | 9 +- .../adapters/flexiband_signal_source.h | 7 +- .../adapters/fmcomms2_signal_source.cc | 2 +- .../adapters/fmcomms2_signal_source.h | 7 +- .../adapters/gen_signal_source.cc | 2 +- .../adapters/gen_signal_source.h | 10 +- .../adapters/gn3s_signal_source.cc | 3 +- .../adapters/gn3s_signal_source.h | 7 +- .../adapters/labsat_signal_source.cc | 2 +- .../adapters/labsat_signal_source.h | 7 +- .../multichannel_file_signal_source.cc | 2 +- .../multichannel_file_signal_source.h | 7 +- .../adapters/nsr_file_signal_source.cc | 2 +- .../adapters/nsr_file_signal_source.h | 7 +- .../adapters/osmosdr_signal_source.cc | 2 +- .../adapters/osmosdr_signal_source.h | 7 +- .../adapters/plutosdr_signal_source.cc | 2 +- .../adapters/plutosdr_signal_source.h | 7 +- .../adapters/raw_array_signal_source.cc | 5 +- .../adapters/raw_array_signal_source.h | 7 +- .../adapters/rtl_tcp_signal_source.cc | 2 +- .../adapters/rtl_tcp_signal_source.h | 7 +- .../adapters/spir_file_signal_source.cc | 2 +- .../adapters/spir_file_signal_source.h | 7 +- .../spir_gss6450_file_signal_source.cc | 2 +- .../spir_gss6450_file_signal_source.h | 7 +- .../two_bit_cpx_file_signal_source.cc | 2 +- .../adapters/two_bit_cpx_file_signal_source.h | 7 +- .../two_bit_packed_file_signal_source.cc | 2 +- .../two_bit_packed_file_signal_source.h | 7 +- .../adapters/uhd_signal_source.cc | 2 +- .../adapters/uhd_signal_source.h | 7 +- .../gnuradio_blocks/labsat23_source.cc | 22 +- .../gnuradio_blocks/labsat23_source.h | 11 +- .../signal_source/libs/CMakeLists.txt | 2 +- .../signal_source/libs/gnss_sdr_valve.cc | 22 +- .../signal_source/libs/gnss_sdr_valve.h | 17 +- src/core/receiver/CMakeLists.txt | 6 +- src/core/receiver/channel_event.cc | 42 + src/core/receiver/channel_event.h | 53 + src/core/receiver/command_event.cc | 42 + src/core/receiver/command_event.h | 53 + src/core/receiver/control_message_factory.cc | 72 -- src/core/receiver/control_message_factory.h | 64 -- src/core/receiver/control_thread.cc | 102 +- src/core/receiver/control_thread.h | 34 +- src/core/receiver/gnss_block_factory.cc | 24 +- src/core/receiver/gnss_block_factory.h | 33 +- src/core/receiver/gnss_flowgraph.cc | 353 +++---- src/core/receiver/gnss_flowgraph.h | 10 +- src/core/receiver/tcp_cmd_interface.cc | 26 +- src/core/receiver/tcp_cmd_interface.h | 7 +- src/tests/data/high_dynamics_signal.bin | Bin 0 -> 168784 bytes src/tests/data/high_dynamics_signal.mat | Bin 0 -> 79823 bytes .../control_message_factory_test.cc | 1 - .../control-plane/control_thread_test.cc | 9 +- .../control-plane/gnss_block_factory_test.cc | 18 +- .../control-plane/gnss_flowgraph_test.cc | 2 +- .../acquisition/acq_performance_test.cc | 2 +- .../beidou_b1i_pcps_acquisition_test.cc | 4 +- .../beidou_b3i_pcps_acquisition_test.cc | 4 +- ...8ms_ambiguous_acquisition_gsoc2013_test.cc | 4 +- ...cps_ambiguous_acquisition_gsoc2013_test.cc | 4 +- ...e1_pcps_ambiguous_acquisition_gsoc_test.cc | 4 +- ...ileo_e1_pcps_ambiguous_acquisition_test.cc | 4 +- ...wsr_ambiguous_acquisition_gsoc2013_test.cc | 4 +- ...ync_ambiguous_acquisition_gsoc2014_test.cc | 2 +- ...ong_ambiguous_acquisition_gsoc2013_test.cc | 4 +- ...cps_acquisition_gsoc2014_gensource_test.cc | 4 +- ...ss_l1_ca_pcps_acquisition_gsoc2017_test.cc | 4 +- .../glonass_l1_ca_pcps_acquisition_test.cc | 4 +- .../glonass_l2_ca_pcps_acquisition_test.cc | 4 +- ...ps_l1_ca_pcps_acquisition_gsoc2013_test.cc | 4 +- .../gps_l1_ca_pcps_acquisition_test.cc | 4 +- .../gps_l1_ca_pcps_acquisition_test_fpga.cc | 2 +- ...a_pcps_opencl_acquisition_gsoc2013_test.cc | 4 +- ...cps_quicksync_acquisition_gsoc2014_test.cc | 4 +- ..._ca_pcps_tong_acquisition_gsoc2013_test.cc | 4 +- .../gps_l2_m_pcps_acquisition_test.cc | 4 +- .../filter/fir_filter_test.cc | 2 +- .../filter/notch_filter_lite_test.cc | 2 +- .../filter/notch_filter_test.cc | 2 +- .../filter/pulse_blanking_filter_test.cc | 2 +- .../observables/hybrid_observables_test.cc | 993 +++++++++--------- .../direct_resampler_conditioner_cc_test.cc | 4 +- .../resampler/mmse_resampler_test.cc | 6 +- .../sources/file_signal_source_test.cc | 2 +- .../sources/gnss_sdr_valve_test.cc | 4 +- .../galileo_e1_dll_pll_veml_tracking_test.cc | 4 +- .../tracking/galileo_e5a_tracking_test.cc | 4 +- ...onass_l1_ca_dll_pll_c_aid_tracking_test.cc | 4 +- .../glonass_l1_ca_dll_pll_tracking_test.cc | 4 +- .../gps_l2_m_dll_pll_tracking_test.cc | 4 +- .../tracking/tracking_pull-in_test.cc | 5 +- src/utils/front-end-cal/main.cc | 2 +- 112 files changed, 1219 insertions(+), 1171 deletions(-) create mode 100644 src/core/receiver/channel_event.cc create mode 100644 src/core/receiver/channel_event.h create mode 100644 src/core/receiver/command_event.cc create mode 100644 src/core/receiver/command_event.h delete mode 100644 src/core/receiver/control_message_factory.cc delete mode 100644 src/core/receiver/control_message_factory.h create mode 100644 src/tests/data/high_dynamics_signal.bin create mode 100644 src/tests/data/high_dynamics_signal.mat diff --git a/src/algorithms/PVT/libs/rtcm.h b/src/algorithms/PVT/libs/rtcm.h index 792eafb9a..75dcd4c50 100644 --- a/src/algorithms/PVT/libs/rtcm.h +++ b/src/algorithms/PVT/libs/rtcm.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include // for size_t #include diff --git a/src/algorithms/channel/adapters/CMakeLists.txt b/src/algorithms/channel/adapters/CMakeLists.txt index 7f439ce56..48f293df5 100644 --- a/src/algorithms/channel/adapters/CMakeLists.txt +++ b/src/algorithms/channel/adapters/CMakeLists.txt @@ -31,6 +31,7 @@ target_link_libraries(channel_adapters Gnuradio::runtime channel_libs core_system_parameters + core_receiver PRIVATE Gflags::gflags Glog::glog diff --git a/src/algorithms/channel/adapters/channel.cc b/src/algorithms/channel/adapters/channel.cc index 98574b3eb..2cea8e915 100644 --- a/src/algorithms/channel/adapters/channel.cc +++ b/src/algorithms/channel/adapters/channel.cc @@ -42,7 +42,7 @@ Channel::Channel(ConfigurationInterface* configuration, uint32_t channel, std::shared_ptr acq, std::shared_ptr trk, std::shared_ptr nav, - std::string role, std::string implementation, gr::msg_queue::sptr queue) + std::string role, std::string implementation, std::shared_ptr > queue) { acq_ = std::move(acq); trk_ = std::move(trk); diff --git a/src/algorithms/channel/adapters/channel.h b/src/algorithms/channel/adapters/channel.h index a238f490c..083608331 100644 --- a/src/algorithms/channel/adapters/channel.h +++ b/src/algorithms/channel/adapters/channel.h @@ -38,10 +38,11 @@ #include "channel_fsm.h" #include "channel_interface.h" #include "channel_msg_receiver_cc.h" +#include "concurrent_queue.h" #include "gnss_signal.h" #include "gnss_synchro.h" #include -#include +#include #include #include #include @@ -66,7 +67,7 @@ public: //! Constructor Channel(ConfigurationInterface* configuration, uint32_t channel, std::shared_ptr acq, std::shared_ptr trk, std::shared_ptr nav, - std::string role, std::string implementation, gr::msg_queue::sptr queue); + std::string role, std::string implementation, std::shared_ptr> queue); virtual ~Channel(); //!< Virtual destructor @@ -105,7 +106,7 @@ private: bool connected_; bool repeat_; std::shared_ptr channel_fsm_; - gr::msg_queue::sptr queue_; + std::shared_ptr> queue_; std::mutex mx; }; diff --git a/src/algorithms/channel/libs/CMakeLists.txt b/src/algorithms/channel/libs/CMakeLists.txt index ba6e2a274..2a5773dfc 100644 --- a/src/algorithms/channel/libs/CMakeLists.txt +++ b/src/algorithms/channel/libs/CMakeLists.txt @@ -38,6 +38,7 @@ target_link_libraries(channel_libs Gnuradio::runtime Gnuradio::pmt core_system_parameters + core_receiver PRIVATE Boost::boost Gflags::gflags diff --git a/src/algorithms/channel/libs/channel_fsm.cc b/src/algorithms/channel/libs/channel_fsm.cc index ac533d310..ffc491634 100644 --- a/src/algorithms/channel/libs/channel_fsm.cc +++ b/src/algorithms/channel/libs/channel_fsm.cc @@ -31,7 +31,7 @@ */ #include "channel_fsm.h" -#include "control_message_factory.h" +#include "channel_event.h" #include #include @@ -179,7 +179,7 @@ void ChannelFsm::set_telemetry(std::shared_ptr teleme } -void ChannelFsm::set_queue(gr::msg_queue::sptr queue) +void ChannelFsm::set_queue(std::shared_ptr> queue) { std::lock_guard lk(mx); queue_ = std::move(queue); @@ -215,29 +215,17 @@ void ChannelFsm::start_acquisition() void ChannelFsm::start_tracking() { trk_->start_tracking(); - std::unique_ptr cmf(new ControlMessageFactory()); - if (queue_ != gr::msg_queue::make()) - { - queue_->handle(cmf->GetQueueMessage(channel_, 1)); - } + queue_->push(pmt::make_any(channel_event_make(channel_, 1))); } void ChannelFsm::request_satellite() { - std::unique_ptr cmf(new ControlMessageFactory()); - if (queue_ != gr::msg_queue::make()) - { - queue_->handle(cmf->GetQueueMessage(channel_, 0)); - } + queue_->push(pmt::make_any(channel_event_make(channel_, 0))); } void ChannelFsm::notify_stop_tracking() { - std::unique_ptr cmf(new ControlMessageFactory()); - if (queue_ != gr::msg_queue::make()) - { - queue_->handle(cmf->GetQueueMessage(channel_, 2)); - } + queue_->push(pmt::make_any(channel_event_make(channel_, 2))); } diff --git a/src/algorithms/channel/libs/channel_fsm.h b/src/algorithms/channel/libs/channel_fsm.h index 8a3342511..a083a1507 100644 --- a/src/algorithms/channel/libs/channel_fsm.h +++ b/src/algorithms/channel/libs/channel_fsm.h @@ -34,9 +34,10 @@ #define GNSS_SDR_CHANNEL_FSM_H #include "acquisition_interface.h" +#include "concurrent_queue.h" #include "telemetry_decoder_interface.h" #include "tracking_interface.h" -#include +#include #include #include #include @@ -54,7 +55,7 @@ public: void set_acquisition(std::shared_ptr acquisition); void set_tracking(std::shared_ptr tracking); void set_telemetry(std::shared_ptr telemetry); - void set_queue(gr::msg_queue::sptr queue); + void set_queue(std::shared_ptr> queue); void set_channel(uint32_t channel); void start_acquisition(); // FSM EVENTS @@ -76,7 +77,7 @@ private: std::shared_ptr acq_; std::shared_ptr trk_; std::shared_ptr nav_; - gr::msg_queue::sptr queue_; + std::shared_ptr> queue_; uint32_t channel_; uint32_t d_state; std::mutex mx; diff --git a/src/algorithms/libs/pass_through.cc b/src/algorithms/libs/pass_through.cc index 1a517a96b..7b4144dd1 100644 --- a/src/algorithms/libs/pass_through.cc +++ b/src/algorithms/libs/pass_through.cc @@ -109,6 +109,12 @@ Pass_Through::Pass_Through(ConfigurationInterface* configuration, const std::str } kludge_copy_ = gr::blocks::copy::make(item_size_); + unsigned long int max_source_buffer_samples = configuration->property("GNSS-SDR.max_source_buffer_samples", 0); + if (max_source_buffer_samples > 0) + { + kludge_copy_->set_max_output_buffer(max_source_buffer_samples); + LOG(INFO) << "Set signal conditioner max output buffer to " << max_source_buffer_samples; + } DLOG(INFO) << "kludge_copy(" << kludge_copy_->unique_id() << ")"; if (in_streams_ > 1) { diff --git a/src/algorithms/signal_generator/adapters/CMakeLists.txt b/src/algorithms/signal_generator/adapters/CMakeLists.txt index fb651871e..a519eaa3f 100644 --- a/src/algorithms/signal_generator/adapters/CMakeLists.txt +++ b/src/algorithms/signal_generator/adapters/CMakeLists.txt @@ -34,6 +34,7 @@ target_link_libraries(signal_generator_adapters Gflags::gflags Glog::glog algorithms_libs + core_receiver ) target_include_directories(signal_generator_adapters diff --git a/src/algorithms/signal_generator/adapters/signal_generator.cc b/src/algorithms/signal_generator/adapters/signal_generator.cc index c4dc9dc3d..31636f246 100644 --- a/src/algorithms/signal_generator/adapters/signal_generator.cc +++ b/src/algorithms/signal_generator/adapters/signal_generator.cc @@ -44,7 +44,7 @@ SignalGenerator::SignalGenerator(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + unsigned int out_stream, std::shared_ptr > queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/gen_source.dat"; diff --git a/src/algorithms/signal_generator/adapters/signal_generator.h b/src/algorithms/signal_generator/adapters/signal_generator.h index e32c431b8..d2adfc27e 100644 --- a/src/algorithms/signal_generator/adapters/signal_generator.h +++ b/src/algorithms/signal_generator/adapters/signal_generator.h @@ -33,12 +33,13 @@ #ifndef GNSS_SDR_SIGNAL_GENERATOR_H_ #define GNSS_SDR_SIGNAL_GENERATOR_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "signal_generator_c.h" #include #include #include -#include +#include #include #include @@ -53,7 +54,7 @@ class SignalGenerator : public GNSSBlockInterface public: SignalGenerator(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr > queue); virtual ~SignalGenerator(); @@ -91,6 +92,6 @@ private: boost::shared_ptr gen_source_; gr::blocks::vector_to_stream::sptr vector_to_stream_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr > queue_; }; #endif /*GNSS_SDR_SIGNAL_GENERATOR_H_*/ diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc index f83c64f25..dac665cc4 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -48,7 +48,7 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/signal_source.dat"; diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h index 9277c4c2b..e5a917199 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h @@ -32,10 +32,11 @@ #ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ #define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "fpga_switch.h" #include "gnss_block_interface.h" #include -#include +#include #include #include @@ -46,7 +47,7 @@ class Ad9361FpgaSignalSource : public GNSSBlockInterface public: Ad9361FpgaSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); ~Ad9361FpgaSignalSource(); @@ -112,7 +113,7 @@ private: bool dump_; std::string dump_filename_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; std::shared_ptr switch_fpga; }; diff --git a/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc b/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc index 024966d0e..a130b32f8 100644 --- a/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/custom_udp_signal_source.cc @@ -40,7 +40,7 @@ CustomUDPSignalSource::CustomUDPSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { // DUMP PARAMETERS std::string empty = ""; diff --git a/src/algorithms/signal_source/adapters/custom_udp_signal_source.h b/src/algorithms/signal_source/adapters/custom_udp_signal_source.h index 37e80caf7..3d8d400de 100644 --- a/src/algorithms/signal_source/adapters/custom_udp_signal_source.h +++ b/src/algorithms/signal_source/adapters/custom_udp_signal_source.h @@ -32,12 +32,13 @@ #ifndef GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H #define GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "gr_complex_ip_packet_source.h" #include #include #include -#include +#include #include #include #include @@ -54,7 +55,7 @@ class CustomUDPSignalSource : public GNSSBlockInterface public: CustomUDPSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~CustomUDPSignalSource(); @@ -98,7 +99,7 @@ private: std::vector> null_sinks_; Gr_Complex_Ip_Packet_Source::sptr udp_gnss_rx_source_; std::vector> file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_CUSTOM_UDP_SIGNAL_SOURCE_H */ diff --git a/src/algorithms/signal_source/adapters/file_signal_source.cc b/src/algorithms/signal_source/adapters/file_signal_source.cc index 59ad90f50..b478b6363 100644 --- a/src/algorithms/signal_source/adapters/file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/file_signal_source.cc @@ -44,7 +44,7 @@ FileSignalSource::FileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "./example_capture.dat"; std::string default_item_type = "short"; diff --git a/src/algorithms/signal_source/adapters/file_signal_source.h b/src/algorithms/signal_source/adapters/file_signal_source.h index bfded2ce8..86d87798a 100644 --- a/src/algorithms/signal_source/adapters/file_signal_source.h +++ b/src/algorithms/signal_source/adapters/file_signal_source.h @@ -35,13 +35,15 @@ #ifndef GNSS_SDR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include #include #include -#include +#include #include +#include #include class ConfigurationInterface; @@ -55,7 +57,7 @@ class FileSignalSource : public GNSSBlockInterface public: FileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~FileSignalSource(); @@ -122,7 +124,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; gr::blocks::throttle::sptr throttle_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; // Throttle control bool enable_throttle_control_; diff --git a/src/algorithms/signal_source/adapters/flexiband_signal_source.cc b/src/algorithms/signal_source/adapters/flexiband_signal_source.cc index ff3f3f9a0..478a6973d 100644 --- a/src/algorithms/signal_source/adapters/flexiband_signal_source.cc +++ b/src/algorithms/signal_source/adapters/flexiband_signal_source.cc @@ -34,7 +34,6 @@ #include "configuration_interface.h" #include #include -#include #include #include @@ -43,10 +42,10 @@ FlexibandSignalSource::FlexibandSignalSource(ConfigurationInterface* configurati const std::string& role, unsigned int in_stream, unsigned int out_stream, - gr::msg_queue::sptr queue) : role_(role), - in_stream_(in_stream), - out_stream_(out_stream), - queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), + in_stream_(in_stream), + out_stream_(out_stream), + queue_(std::move(queue)) { std::string default_item_type = "byte"; item_type_ = configuration->property(role + ".item_type", default_item_type); diff --git a/src/algorithms/signal_source/adapters/flexiband_signal_source.h b/src/algorithms/signal_source/adapters/flexiband_signal_source.h index 7da5839a8..56c2aff09 100644 --- a/src/algorithms/signal_source/adapters/flexiband_signal_source.h +++ b/src/algorithms/signal_source/adapters/flexiband_signal_source.h @@ -34,13 +34,14 @@ #ifndef GNSS_SDR_FLEXIBAND_SIGNAL_SOURCE_H_ #define GNSS_SDR_FLEXIBAND_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include #include #include #include -#include +#include #include #include @@ -56,7 +57,7 @@ class FlexibandSignalSource : public GNSSBlockInterface public: FlexibandSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~FlexibandSignalSource(); @@ -109,7 +110,7 @@ private: std::vector> float_to_complex_; std::vector null_sinks_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif // GNSS_SDR_FLEXIBAND_SIGNAL_SOURCE_H_ diff --git a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc index 704c5b01e..bfc470dbc 100644 --- a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc +++ b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.cc @@ -43,7 +43,7 @@ Fmcomms2SignalSource::Fmcomms2SignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/signal_source.dat"; diff --git a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h index 1388a514d..44870c182 100644 --- a/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h +++ b/src/algorithms/signal_source/adapters/fmcomms2_signal_source.h @@ -41,7 +41,8 @@ #else #include #endif -#include +#include "concurrent_queue.h" +#include #include class ConfigurationInterface; @@ -51,7 +52,7 @@ class Fmcomms2SignalSource : public GNSSBlockInterface public: Fmcomms2SignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~Fmcomms2SignalSource(); @@ -122,7 +123,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_FMCOMMS2_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/gen_signal_source.cc b/src/algorithms/signal_source/adapters/gen_signal_source.cc index ef8441853..057650ac0 100644 --- a/src/algorithms/signal_source/adapters/gen_signal_source.cc +++ b/src/algorithms/signal_source/adapters/gen_signal_source.cc @@ -42,7 +42,7 @@ // Constructor GenSignalSource::GenSignalSource(GNSSBlockInterface *signal_generator, GNSSBlockInterface *filter, - std::string role, boost::shared_ptr queue) : signal_generator_(signal_generator), + std::string role, std::shared_ptr> queue) : signal_generator_(signal_generator), filter_(filter), role_(std::move(role)), queue_(std::move(queue)) diff --git a/src/algorithms/signal_source/adapters/gen_signal_source.h b/src/algorithms/signal_source/adapters/gen_signal_source.h index 49fb25293..d30f8935b 100644 --- a/src/algorithms/signal_source/adapters/gen_signal_source.h +++ b/src/algorithms/signal_source/adapters/gen_signal_source.h @@ -34,8 +34,9 @@ #define GNSS_SDR_GEN_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" -#include +#include #include /*! @@ -47,7 +48,7 @@ class GenSignalSource : public GNSSBlockInterface public: //! Constructor GenSignalSource(GNSSBlockInterface *signal_generator, GNSSBlockInterface *filter, - std::string role, boost::shared_ptr queue); + std::string role, std::shared_ptr> queue); //! Virtual destructor virtual ~GenSignalSource(); @@ -58,20 +59,17 @@ public: gr::basic_block_sptr get_right_block() override; inline std::string role() override { return role_; } - //! Returns "Signal Source" inline std::string implementation() override { return "Signal Source"; } inline size_t item_size() override { return 0; } - inline GNSSBlockInterface *signal_generator() const { return signal_generator_; } - private: GNSSBlockInterface *signal_generator_; GNSSBlockInterface *filter_; std::string role_; std::string implementation_; bool connected_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_GEN_SIGNAL_SOURCE_H*/ diff --git a/src/algorithms/signal_source/adapters/gn3s_signal_source.cc b/src/algorithms/signal_source/adapters/gn3s_signal_source.cc index 3f66591e9..4a699d09d 100644 --- a/src/algorithms/signal_source/adapters/gn3s_signal_source.cc +++ b/src/algorithms/signal_source/adapters/gn3s_signal_source.cc @@ -32,12 +32,11 @@ #include "configuration_interface.h" #include #include -#include #include Gn3sSignalSource::Gn3sSignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + std::string role, unsigned int in_stream, unsigned int out_stream, std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { std::string default_item_type = "short"; std::string default_dump_file = "./data/gn3s_source.dat"; diff --git a/src/algorithms/signal_source/adapters/gn3s_signal_source.h b/src/algorithms/signal_source/adapters/gn3s_signal_source.h index df799f019..e34b91afe 100644 --- a/src/algorithms/signal_source/adapters/gn3s_signal_source.h +++ b/src/algorithms/signal_source/adapters/gn3s_signal_source.h @@ -32,10 +32,11 @@ #ifndef GNSS_SDR_GN3S_SIGNAL_SOURCE_H_ #define GNSS_SDR_GN3S_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include -#include +#include #include @@ -49,7 +50,7 @@ class Gn3sSignalSource : public GNSSBlockInterface public: Gn3sSignalSource(ConfigurationInterface* configuration, std::string role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~Gn3sSignalSource(); @@ -87,7 +88,7 @@ private: std::string dump_filename_; gr::block_sptr gn3s_source_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_GN3S_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/labsat_signal_source.cc b/src/algorithms/signal_source/adapters/labsat_signal_source.cc index 2fb8ba3b7..e6366261a 100644 --- a/src/algorithms/signal_source/adapters/labsat_signal_source.cc +++ b/src/algorithms/signal_source/adapters/labsat_signal_source.cc @@ -37,7 +37,7 @@ LabsatSignalSource::LabsatSignalSource(ConfigurationInterface* configuration, - const std::string& role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + const std::string& role, unsigned int in_stream, unsigned int out_stream, std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./labsat_output.dat"; diff --git a/src/algorithms/signal_source/adapters/labsat_signal_source.h b/src/algorithms/signal_source/adapters/labsat_signal_source.h index 1d9e333bf..9bf5d2057 100644 --- a/src/algorithms/signal_source/adapters/labsat_signal_source.h +++ b/src/algorithms/signal_source/adapters/labsat_signal_source.h @@ -32,10 +32,11 @@ #ifndef GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_ #define GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include -#include +#include #include class ConfigurationInterface; @@ -48,7 +49,7 @@ class LabsatSignalSource : public GNSSBlockInterface public: LabsatSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~LabsatSignalSource(); @@ -86,7 +87,7 @@ private: std::string dump_filename_; gr::block_sptr labsat23_source_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_LABSAT_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc index 11efe4fd9..330b3e43c 100644 --- a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc @@ -43,7 +43,7 @@ MultichannelFileSignalSource::MultichannelFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "./example_capture.dat"; std::string default_item_type = "short"; diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h index b248073dd..db3a9c57c 100644 --- a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h @@ -35,12 +35,13 @@ #ifndef GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include #include #include -#include +#include #include #include #include @@ -56,7 +57,7 @@ class MultichannelFileSignalSource : public GNSSBlockInterface public: MultichannelFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~MultichannelFileSignalSource(); @@ -122,7 +123,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; std::vector throttle_vec_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; // Throttle control bool enable_throttle_control_; diff --git a/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc b/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc index aa31e75a6..dc00bcecb 100644 --- a/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/nsr_file_signal_source.cc @@ -44,7 +44,7 @@ NsrFileSignalSource::NsrFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "byte"; diff --git a/src/algorithms/signal_source/adapters/nsr_file_signal_source.h b/src/algorithms/signal_source/adapters/nsr_file_signal_source.h index a2b3ee547..2efaa09b3 100644 --- a/src/algorithms/signal_source/adapters/nsr_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/nsr_file_signal_source.h @@ -35,13 +35,14 @@ #ifndef GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_NSR_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "unpack_byte_2bit_samples.h" #include #include #include #include -#include +#include #include class ConfigurationInterface; @@ -55,7 +56,7 @@ class NsrFileSignalSource : public GNSSBlockInterface public: NsrFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~NsrFileSignalSource(); inline std::string role() override @@ -122,7 +123,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; gr::blocks::throttle::sptr throttle_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; // Throttle control bool enable_throttle_control_; diff --git a/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc b/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc index 32ea28cf0..38f823248 100644 --- a/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc +++ b/src/algorithms/signal_source/adapters/osmosdr_signal_source.cc @@ -42,7 +42,7 @@ OsmosdrSignalSource::OsmosdrSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { // DUMP PARAMETERS std::string empty = ""; diff --git a/src/algorithms/signal_source/adapters/osmosdr_signal_source.h b/src/algorithms/signal_source/adapters/osmosdr_signal_source.h index 15f38b2a3..8a96f32d6 100644 --- a/src/algorithms/signal_source/adapters/osmosdr_signal_source.h +++ b/src/algorithms/signal_source/adapters/osmosdr_signal_source.h @@ -33,10 +33,11 @@ #ifndef GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H_ #define GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include -#include +#include #include #include #include @@ -54,7 +55,7 @@ class OsmosdrSignalSource : public GNSSBlockInterface public: OsmosdrSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~OsmosdrSignalSource(); @@ -110,7 +111,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_OSMOSDR_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc b/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc index fc41bd3a9..ba6af1fd6 100644 --- a/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc +++ b/src/algorithms/signal_source/adapters/plutosdr_signal_source.cc @@ -39,7 +39,7 @@ PlutosdrSignalSource::PlutosdrSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/signal_source.dat"; diff --git a/src/algorithms/signal_source/adapters/plutosdr_signal_source.h b/src/algorithms/signal_source/adapters/plutosdr_signal_source.h index e765ff7c4..bc105d171 100644 --- a/src/algorithms/signal_source/adapters/plutosdr_signal_source.h +++ b/src/algorithms/signal_source/adapters/plutosdr_signal_source.h @@ -40,7 +40,8 @@ #else #include #endif -#include +#include "concurrent_queue.h" +#include #include @@ -53,7 +54,7 @@ class PlutosdrSignalSource : public GNSSBlockInterface public: PlutosdrSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~PlutosdrSignalSource(); @@ -109,7 +110,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_PLUTOSDR_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/raw_array_signal_source.cc b/src/algorithms/signal_source/adapters/raw_array_signal_source.cc index f9aab0987..d54a7cb19 100644 --- a/src/algorithms/signal_source/adapters/raw_array_signal_source.cc +++ b/src/algorithms/signal_source/adapters/raw_array_signal_source.cc @@ -29,15 +29,16 @@ */ #include "raw_array_signal_source.h" +#include "concurrent_queue.h" #include "configuration_interface.h" #include #include -#include +#include #include RawArraySignalSource::RawArraySignalSource(ConfigurationInterface* configuration, - std::string role, unsigned int in_stream, unsigned int out_stream, gr::msg_queue::sptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) + std::string role, unsigned int in_stream, unsigned int out_stream, std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) { std::string default_item_type = "gr_complex"; std::string default_dump_file = "./data/raw_array_source.dat"; diff --git a/src/algorithms/signal_source/adapters/raw_array_signal_source.h b/src/algorithms/signal_source/adapters/raw_array_signal_source.h index 321895cef..750efb3fe 100644 --- a/src/algorithms/signal_source/adapters/raw_array_signal_source.h +++ b/src/algorithms/signal_source/adapters/raw_array_signal_source.h @@ -32,10 +32,11 @@ #ifndef GNSS_SDR_RAW_ARRAY_SIGNAL_SOURCE_H_ #define GNSS_SDR_RAW_ARRAY_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include -#include +#include #include class ConfigurationInterface; @@ -48,7 +49,7 @@ class RawArraySignalSource : public GNSSBlockInterface public: RawArraySignalSource(ConfigurationInterface* configuration, std::string role, unsigned int in_stream, - unsigned int out_stream, gr::msg_queue::sptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~RawArraySignalSource(); @@ -87,7 +88,7 @@ private: std::string eth_device_; gr::block_sptr raw_array_source_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_RAW_ARRAY_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc index 2b9574708..478e6b1c7 100644 --- a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.cc @@ -45,7 +45,7 @@ RtlTcpSignalSource::RtlTcpSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) diff --git a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h index 74f2b02d5..2fcb9d871 100644 --- a/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h +++ b/src/algorithms/signal_source/adapters/rtl_tcp_signal_source.h @@ -32,13 +32,14 @@ #ifndef GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H #define GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "rtl_tcp_signal_source_c.h" #include #include #include #include -#include +#include #include #include @@ -57,7 +58,7 @@ public: const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~RtlTcpSignalSource(); @@ -113,7 +114,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_RTL_TCP_SIGNAL_SOURCE_H */ diff --git a/src/algorithms/signal_source/adapters/spir_file_signal_source.cc b/src/algorithms/signal_source/adapters/spir_file_signal_source.cc index 52964abba..91287020c 100644 --- a/src/algorithms/signal_source/adapters/spir_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/spir_file_signal_source.cc @@ -43,7 +43,7 @@ SpirFileSignalSource::SpirFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_item_type = "int"; diff --git a/src/algorithms/signal_source/adapters/spir_file_signal_source.h b/src/algorithms/signal_source/adapters/spir_file_signal_source.h index ad76ce23b..09aff8c09 100644 --- a/src/algorithms/signal_source/adapters/spir_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/spir_file_signal_source.h @@ -32,13 +32,14 @@ #ifndef GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_SPIR_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "unpack_intspir_1bit_samples.h" #include #include #include #include -#include +#include #include #include @@ -53,7 +54,7 @@ class SpirFileSignalSource : public GNSSBlockInterface public: SpirFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~SpirFileSignalSource(); inline std::string role() override @@ -120,7 +121,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; gr::blocks::throttle::sptr throttle_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; // Throttle control bool enable_throttle_control_; diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc index 7e1c3f1ce..1ba2d5bf0 100644 --- a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.cc @@ -40,7 +40,7 @@ SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, - const std::string& role, uint32_t in_streams, uint32_t out_streams, gr::msg_queue::sptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) + const std::string& role, uint32_t in_streams, uint32_t out_streams, std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) { std::string default_filename = "../data/my_capture.dat"; std::string default_dump_filename = "../data/my_capture_dump.dat"; diff --git a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h index 0757c24af..61edd479c 100644 --- a/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/spir_gss6450_file_signal_source.h @@ -32,6 +32,7 @@ #ifndef GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_SPIR_GSS6450_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "gnss_sdr_valve.h" #include "unpack_spir_gss6450_samples.h" @@ -42,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,7 +59,7 @@ class SpirGSS6450FileSignalSource : public GNSSBlockInterface { public: SpirGSS6450FileSignalSource(ConfigurationInterface* configuration, const std::string& role, - uint32_t in_streams, uint32_t out_streams, gr::msg_queue::sptr queue); + uint32_t in_streams, uint32_t out_streams, std::shared_ptr> queue); virtual ~SpirGSS6450FileSignalSource(); inline std::string role() override @@ -131,7 +132,7 @@ private: std::vector> valve_vec_; std::vector sink_vec_; std::vector throttle_vec_; - gr::msg_queue::sptr queue_; + std::shared_ptr> queue_; size_t item_size_; }; diff --git a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc index 604f9c536..9e0b802d4 100644 --- a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.cc @@ -45,7 +45,7 @@ TwoBitCpxFileSignalSource::TwoBitCpxFileSignalSource(ConfigurationInterface* con const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) diff --git a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h index a66a87965..dea315cec 100644 --- a/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/two_bit_cpx_file_signal_source.h @@ -34,6 +34,7 @@ #ifndef GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_TWO_BIT_CPX_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "unpack_byte_2bit_cpx_samples.h" #include @@ -41,7 +42,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +60,7 @@ public: const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~TwoBitCpxFileSignalSource(); inline std::string role() override @@ -127,7 +128,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; gr::blocks::throttle::sptr throttle_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; // Throttle control bool enable_throttle_control_; diff --git a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc index 684cb5b86..4b0c00345 100644 --- a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc +++ b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.cc @@ -47,7 +47,7 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(ConfigurationInterfac const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue) : role_(role), + std::shared_ptr> queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) diff --git a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h index 1e98d737b..ea2bb2d5a 100644 --- a/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h +++ b/src/algorithms/signal_source/adapters/two_bit_packed_file_signal_source.h @@ -35,6 +35,7 @@ #ifndef GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H_ #define GNSS_SDR_TWO_BIT_PACKED_FILE_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include "unpack_2bit_samples.h" #include @@ -42,7 +43,7 @@ #include #include #include -#include +#include #include #include @@ -58,7 +59,7 @@ class TwoBitPackedFileSignalSource : public GNSSBlockInterface public: TwoBitPackedFileSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, - boost::shared_ptr queue); + std::shared_ptr> queue); virtual ~TwoBitPackedFileSignalSource(); inline std::string role() override @@ -146,7 +147,7 @@ private: boost::shared_ptr valve_; gr::blocks::file_sink::sptr sink_; gr::blocks::throttle::sptr throttle_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; size_t item_size_; bool big_endian_items_; bool big_endian_bytes_; diff --git a/src/algorithms/signal_source/adapters/uhd_signal_source.cc b/src/algorithms/signal_source/adapters/uhd_signal_source.cc index ee58eb551..646d2ad00 100644 --- a/src/algorithms/signal_source/adapters/uhd_signal_source.cc +++ b/src/algorithms/signal_source/adapters/uhd_signal_source.cc @@ -42,7 +42,7 @@ UhdSignalSource::UhdSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, unsigned int out_stream, - boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) + std::shared_ptr> queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(std::move(queue)) { // DUMP PARAMETERS std::string empty = ""; diff --git a/src/algorithms/signal_source/adapters/uhd_signal_source.h b/src/algorithms/signal_source/adapters/uhd_signal_source.h index 50d233c2e..232f6934f 100644 --- a/src/algorithms/signal_source/adapters/uhd_signal_source.h +++ b/src/algorithms/signal_source/adapters/uhd_signal_source.h @@ -31,12 +31,13 @@ #ifndef GNSS_SDR_UHD_SIGNAL_SOURCE_H_ #define GNSS_SDR_UHD_SIGNAL_SOURCE_H_ +#include "concurrent_queue.h" #include "gnss_block_interface.h" #include #include #include -#include #include +#include #include #include #include @@ -52,7 +53,7 @@ class UhdSignalSource : public GNSSBlockInterface public: UhdSignalSource(ConfigurationInterface* configuration, const std::string& role, unsigned int in_stream, - unsigned int out_stream, boost::shared_ptr queue); + unsigned int out_stream, std::shared_ptr> queue); virtual ~UhdSignalSource(); @@ -107,7 +108,7 @@ private: std::vector> valve_; std::vector file_sink_; - boost::shared_ptr queue_; + std::shared_ptr> queue_; }; #endif /*GNSS_SDR_UHD_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc index 06972a25a..366eb558f 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc @@ -30,7 +30,8 @@ #include "labsat23_source.h" -#include "control_message_factory.h" +#include "command_event.h" +#include #include #include #include @@ -39,7 +40,7 @@ #include -labsat23_source_sptr labsat23_make_source_sptr(const char *signal_file_basename, int channel_selector, gr::msg_queue::sptr queue) +labsat23_source_sptr labsat23_make_source_sptr(const char *signal_file_basename, int channel_selector, std::shared_ptr> queue) { return labsat23_source_sptr(new labsat23_source(signal_file_basename, channel_selector, std::move(queue))); } @@ -47,10 +48,10 @@ labsat23_source_sptr labsat23_make_source_sptr(const char *signal_file_basename, labsat23_source::labsat23_source(const char *signal_file_basename, int channel_selector, - gr::msg_queue::sptr queue) : gr::block("labsat23_source", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(1, 1, sizeof(gr_complex))), - d_queue(std::move(queue)) + std::shared_ptr> queue) : gr::block("labsat23_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_queue(std::move(queue)) { if (channel_selector < 1 or channel_selector > 2) { @@ -467,9 +468,8 @@ int labsat23_source::general_work(int noutput_items, { std::cout << "End of file reached, LabSat source stop" << std::endl; } - auto *cmf = new ControlMessageFactory(); - d_queue->handle(cmf->GetQueueMessage(200, 0)); - delete cmf; + + d_queue->push(pmt::make_any(command_event_make(200, 0))); return -1; } } @@ -528,9 +528,7 @@ int labsat23_source::general_work(int noutput_items, { std::cout << "End of file reached, LabSat source stop" << std::endl; } - auto *cmf = new ControlMessageFactory(); - d_queue->handle(cmf->GetQueueMessage(200, 0)); - delete cmf; + d_queue->push(pmt::make_any(command_event_make(200, 0))); return -1; } } diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h index a09c0f3a8..49c74bc61 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h @@ -31,8 +31,9 @@ #ifndef GNSS_SDR_LABSAT23_SOURCE_H #define GNSS_SDR_LABSAT23_SOURCE_H +#include "concurrent_queue.h" #include -#include // for msg_queue, msg_queue::sptr +#include #include #include #include @@ -45,7 +46,7 @@ using labsat23_source_sptr = boost::shared_ptr; labsat23_source_sptr labsat23_make_source_sptr( const char *signal_file_basename, int channel_selector, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); /*! * \brief This class implements conversion between Labsat2 and 3 format byte packet samples to gr_complex @@ -64,11 +65,11 @@ private: friend labsat23_source_sptr labsat23_make_source_sptr( const char *signal_file_basename, int channel_selector, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); labsat23_source(const char *signal_file_basename, int channel_selector, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::string generate_filename(); void decode_samples_one_channel(int16_t input_short, gr_complex *out, int type); @@ -82,7 +83,7 @@ private: std::ifstream *binary_input_file; uint8_t d_ref_clock; uint8_t d_bits_per_sample; - gr::msg_queue::sptr d_queue; + std::shared_ptr> d_queue; }; #endif diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index f6015ec59..1045967b4 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -71,10 +71,10 @@ target_link_libraries(signal_source_libs PUBLIC Boost::boost Gnuradio::runtime + core_receiver PRIVATE Gflags::gflags Glog::glog - core_receiver ) if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) diff --git a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc index 615cb65b7..7a5fc18a9 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc +++ b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc @@ -32,17 +32,17 @@ */ #include "gnss_sdr_valve.h" -#include "control_message_factory.h" // for ControlMessageFactory -#include // for LOG -#include // for io_signature -#include // for min -#include // for memcpy -#include // for usleep +#include "command_event.h" +#include // for LOG +#include // for io_signature +#include // for min +#include // for memcpy +#include // for usleep #include Gnss_Sdr_Valve::Gnss_Sdr_Valve(size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue, + std::shared_ptr> queue, bool stop_flowgraph) : gr::sync_block("valve", gr::io_signature::make(1, 20, sizeof_stream_item), gr::io_signature::make(1, 20, sizeof_stream_item)), @@ -55,14 +55,14 @@ Gnss_Sdr_Valve::Gnss_Sdr_Valve(size_t sizeof_stream_item, } -boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue, bool stop_flowgraph) +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, std::shared_ptr> queue, bool stop_flowgraph) { boost::shared_ptr valve_(new Gnss_Sdr_Valve(sizeof_stream_item, nitems, std::move(queue), stop_flowgraph)); return valve_; } -boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue) +boost::shared_ptr gnss_sdr_make_valve(size_t sizeof_stream_item, uint64_t nitems, std::shared_ptr> queue) { boost::shared_ptr valve_(new Gnss_Sdr_Valve(sizeof_stream_item, nitems, std::move(queue), true)); return valve_; @@ -83,10 +83,8 @@ int Gnss_Sdr_Valve::work(int noutput_items, { if (d_ncopied_items >= d_nitems) { - auto *cmf = new ControlMessageFactory(); - d_queue->handle(cmf->GetQueueMessage(200, 0)); LOG(INFO) << "Stopping receiver, " << d_ncopied_items << " samples processed"; - delete cmf; + d_queue->push(pmt::make_any(command_event_make(200, 0))); if (d_stop_flowgraph) { return -1; // Done! diff --git a/src/algorithms/signal_source/libs/gnss_sdr_valve.h b/src/algorithms/signal_source/libs/gnss_sdr_valve.h index b56807c2b..6c28f28f5 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_valve.h +++ b/src/algorithms/signal_source/libs/gnss_sdr_valve.h @@ -34,11 +34,12 @@ #ifndef GNSS_SDR_GNSS_SDR_VALVE_H_ #define GNSS_SDR_GNSS_SDR_VALVE_H_ +#include "concurrent_queue.h" #include -#include // for msg_queue, msg_queue::sptr #include // for sync_block #include // for gr_vector_const_void_star -#include // for size_t +#include +#include // for size_t #include class Gnss_Sdr_Valve; @@ -46,12 +47,12 @@ class Gnss_Sdr_Valve; boost::shared_ptr gnss_sdr_make_valve( size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); boost::shared_ptr gnss_sdr_make_valve( size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue, + std::shared_ptr> queue, bool stop_flowgraph); /*! @@ -71,21 +72,21 @@ private: friend boost::shared_ptr gnss_sdr_make_valve( size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); friend boost::shared_ptr gnss_sdr_make_valve( size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue, + std::shared_ptr> queue, bool stop_flowgraph); Gnss_Sdr_Valve(size_t sizeof_stream_item, uint64_t nitems, - gr::msg_queue::sptr queue, bool stop_flowgraph); + std::shared_ptr> queue, bool stop_flowgraph); uint64_t d_nitems; uint64_t d_ncopied_items; - gr::msg_queue::sptr d_queue; + std::shared_ptr> d_queue; bool d_stop_flowgraph; bool d_open_valve; }; diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index 83d684906..7f80fddbd 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -19,17 +19,17 @@ set(GNSS_RECEIVER_SOURCES control_thread.cc - control_message_factory.cc file_configuration.cc gnss_block_factory.cc gnss_flowgraph.cc in_memory_configuration.cc tcp_cmd_interface.cc + channel_event.cc + command_event.cc ) set(GNSS_RECEIVER_HEADERS control_thread.h - control_message_factory.h file_configuration.h gnss_block_factory.h gnss_flowgraph.h @@ -38,6 +38,8 @@ set(GNSS_RECEIVER_HEADERS concurrent_map.h concurrent_queue.h control_message.h + channel_event.h + command_event.h ) list(SORT GNSS_RECEIVER_HEADERS) diff --git a/src/core/receiver/channel_event.cc b/src/core/receiver/channel_event.cc new file mode 100644 index 000000000..7c6862d76 --- /dev/null +++ b/src/core/receiver/channel_event.cc @@ -0,0 +1,42 @@ +/*! + * \file channel_event.cc + * \brief Class that defines a channel event + * \author Javier Arribas, 2019. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "channel_event.h" + +channel_event_sptr channel_event_make(int channel_id, int event_type) +{ + return channel_event_sptr(new channel_event(channel_id, event_type)); +} + +channel_event::channel_event(int channel_id_, int event_type_) +{ + channel_id = channel_id_; + event_type = event_type_; +} diff --git a/src/core/receiver/channel_event.h b/src/core/receiver/channel_event.h new file mode 100644 index 000000000..51c1a3a8f --- /dev/null +++ b/src/core/receiver/channel_event.h @@ -0,0 +1,53 @@ +/*! + * \file channel_event.h + * \brief Class that defines a channel event + * \author Javier Arribas, 2019. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_CHANNEL_EVENT_H +#define GNSS_SDR_CHANNEL_EVENT_H + +#include + +class channel_event; + +using channel_event_sptr = std::shared_ptr; + +channel_event_sptr channel_event_make(int channel_id, int event_type); + +class channel_event +{ +public: + int channel_id; + int event_type; +private: + friend channel_event_sptr channel_event_make(int channel_id, int event_type); + channel_event(int channel_id_, int event_type_); + +}; + +#endif diff --git a/src/core/receiver/command_event.cc b/src/core/receiver/command_event.cc new file mode 100644 index 000000000..771061255 --- /dev/null +++ b/src/core/receiver/command_event.cc @@ -0,0 +1,42 @@ +/*! + * \file command_event.cc + * \brief Class that defines a receiver command event + * \author Javier Arribas, 2019. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "command_event.h" + +command_event_sptr command_event_make(int command_id, int event_type) +{ + return command_event_sptr(new command_event(command_id, event_type)); +} + +command_event::command_event(int command_id_, int event_type_) +{ + command_id = command_id_; + event_type = event_type_; +} diff --git a/src/core/receiver/command_event.h b/src/core/receiver/command_event.h new file mode 100644 index 000000000..094281578 --- /dev/null +++ b/src/core/receiver/command_event.h @@ -0,0 +1,53 @@ +/*! + * \file command_event.h + * \brief Class that defines a receiver command event + * \author Javier Arribas, 2019. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_command_EVENT_H +#define GNSS_SDR_command_EVENT_H + +#include + +class command_event; + +using command_event_sptr = std::shared_ptr; + +command_event_sptr command_event_make(int command_id, int event_type); + +class command_event +{ +public: + int command_id; + int event_type; + +private: + friend command_event_sptr command_event_make(int command_id, int event_type); + command_event(int command_id_, int event_type_); +}; + +#endif diff --git a/src/core/receiver/control_message_factory.cc b/src/core/receiver/control_message_factory.cc deleted file mode 100644 index 566f884a4..000000000 --- a/src/core/receiver/control_message_factory.cc +++ /dev/null @@ -1,72 +0,0 @@ -/*! - * \file control_message_factory.cc - * \brief Implementation of a Control Message Factory - * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "control_message_factory.h" -#include -#include // for memcpy -#include // for operator<<, basic_ostream - -// Constructor -ControlMessageFactory::ControlMessageFactory() = default; - - -// Destructor -ControlMessageFactory::~ControlMessageFactory() = default; - - -gr::message::sptr ControlMessageFactory::GetQueueMessage(unsigned int who, unsigned int what) -{ - std::shared_ptr control_message = std::make_shared(); - control_message->who = who; - control_message->what = what; - gr::message::sptr queue_message = gr::message::make(0, 0, 0, sizeof(ControlMessage)); - memcpy(queue_message->msg(), control_message.get(), sizeof(ControlMessage)); - return queue_message; -} - - -std::shared_ptr>> ControlMessageFactory::GetControlMessages(const gr::message::sptr queue_message) // NOLINT(performance-unnecessary-value-param) -{ - std::shared_ptr>> control_messages = std::make_shared>>(); - unsigned int control_messages_count = queue_message->length() / sizeof(ControlMessage); - if (queue_message->length() % sizeof(ControlMessage) != 0) - { - LOG(WARNING) << "Queue message has size " << queue_message->length() << ", which is not" - << " multiple of control message size " << sizeof(ControlMessage); - LOG(WARNING) << "Ignoring this queue message to prevent unexpected results."; - return control_messages; - } - for (unsigned int i = 0; i < control_messages_count; i++) - { - control_messages->push_back(std::make_shared()); - memcpy(control_messages->at(i).get(), queue_message->msg() + (i * sizeof(ControlMessage)), sizeof(ControlMessage)); - } - return control_messages; -} diff --git a/src/core/receiver/control_message_factory.h b/src/core/receiver/control_message_factory.h deleted file mode 100644 index f8a4666f6..000000000 --- a/src/core/receiver/control_message_factory.h +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * \file control_message_factory.h - * \brief Interface of a factory for control messages. - * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_ -#define GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_ - -#include -#include -#include - -//! Message described by who sent it and what it says -typedef struct control_message -{ - unsigned int who; - unsigned int what; -} ControlMessage; - - -/*! - * \brief This class implements a factory for Control Messages. - * - * It encapsulates the complexity behind getting Queue Messages and associated Control Messages - */ -class ControlMessageFactory -{ -public: - //! Constructor - ControlMessageFactory(); - - //! Virtual destructor - virtual ~ControlMessageFactory(); - - gr::message::sptr GetQueueMessage(unsigned int who, unsigned int what); - std::shared_ptr>> GetControlMessages(const gr::message::sptr queue_message); // NOLINT(performance-unnecessary-value-param) -}; - -#endif /*GNSS_SDR_CONTROL_MESSAGE_FACTORY_H_*/ diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index 384d6f041..154f9ec7b 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -34,9 +34,7 @@ #include "control_thread.h" #include "concurrent_map.h" -#include "concurrent_queue.h" #include "configuration_interface.h" -#include "control_message_factory.h" #include "file_configuration.h" #include "galileo_almanac.h" #include "galileo_ephemeris.h" @@ -110,7 +108,7 @@ ControlThread::ControlThread(std::shared_ptr configurati void ControlThread::init() { // Instantiates a control queue, a GNSS flowgraph, and a control message factory - control_queue_ = gr::msg_queue::make(0); + control_queue_ = std::make_shared>(); cmd_interface_.set_msg_queue(control_queue_); //set also the queue pointer for the telecommand thread try { @@ -120,7 +118,6 @@ void ControlThread::init() { std::cout << "Caught bad lexical cast with error " << e.what() << std::endl; } - control_message_factory_ = std::make_shared(); stop_ = false; processed_control_messages_ = 0; applied_actions_ = 0; @@ -287,12 +284,13 @@ int ControlThread::run() // Main loop to read and process the control messages while (flowgraph_->running() && !stop_) { - //TODO re-enable the blocking read messages functions and fork the process - read_control_messages(); - if (control_messages_ != nullptr) - { - process_control_messages(); - } + //TODO call here the new sat dispatcher and receiver controller + // read_control_messages(); + // if (control_messages_ != nullptr) + // { + // process_control_messages(); + // } + std::cout << "tick\n"; } std::cout << "Stopping GNSS-SDR, please wait!" << std::endl; flowgraph_->stop(); @@ -325,7 +323,7 @@ int ControlThread::run() } -void ControlThread::set_control_queue(const gr::msg_queue::sptr control_queue) // NOLINT(performance-unnecessary-value-param) +void ControlThread::set_control_queue(const std::shared_ptr> control_queue) // NOLINT(performance-unnecessary-value-param) { if (flowgraph_->running()) { @@ -794,42 +792,42 @@ void ControlThread::assist_GNSS() void ControlThread::read_control_messages() { DLOG(INFO) << "Reading control messages from queue"; - gr::message::sptr queue_message = control_queue_->delete_head(); - if (queue_message != nullptr) - { - control_messages_ = control_message_factory_->GetControlMessages(queue_message); - } - else - { - control_messages_->clear(); - } + // gr::message::sptr queue_message = control_queue_->delete_head(); + // if (queue_message != nullptr) + // { + // control_messages_ = control_message_factory_->GetControlMessages(queue_message); + // } + // else + // { + // control_messages_->clear(); + // } } // Apply the corresponding control actions void ControlThread::process_control_messages() { - for (auto &i : *control_messages_) - { - if (stop_) - { - break; - } - if (i->who == 200) - { - apply_action(i->what); - } - else - { - if (i->who == 300) // some TC commands require also actions from control_thread - { - apply_action(i->what); - } - flowgraph_->apply_action(i->who, i->what); - } - processed_control_messages_++; - } - control_messages_->clear(); + // for (auto &i : *control_messages_) + // { + // if (stop_) + // { + // break; + // } + // if (i->who == 200) + // { + // apply_action(i->what); + // } + // else + // { + // if (i->who == 300) // some TC commands require also actions from control_thread + // { + // apply_action(i->what); + // } + // flowgraph_->apply_action(i->who, i->what); + // } + // processed_control_messages_++; + // } + // control_messages_->clear(); DLOG(INFO) << "Processed all control messages"; } @@ -1092,11 +1090,12 @@ void ControlThread::sysv_queue_listener() if ((std::abs(received_message - (-200.0)) < 10 * std::numeric_limits::epsilon())) { std::cout << "Quit order received, stopping GNSS-SDR !!" << std::endl; - std::unique_ptr cmf(new ControlMessageFactory()); - if (control_queue_ != gr::msg_queue::sptr()) - { - control_queue_->handle(cmf->GetQueueMessage(200, 0)); - } + //todo: remplace old shutdown mechanism + // std::unique_ptr cmf(new ControlMessageFactory()); + // if (control_queue_ != std::shared_ptr>()) + // { + // control_queue_->handle(cmf->GetQueueMessage(200, 0)); + // } read_queue = false; } } @@ -1114,11 +1113,12 @@ void ControlThread::keyboard_listener() if (c == 'q') { std::cout << "Quit keystroke order received, stopping GNSS-SDR !!" << std::endl; - std::unique_ptr cmf(new ControlMessageFactory()); - if (control_queue_ != gr::msg_queue::sptr()) - { - control_queue_->handle(cmf->GetQueueMessage(200, 0)); - } + //todo: remplace old shutdown mechanism + // std::unique_ptr cmf(new ControlMessageFactory()); + // if (control_queue_ != std::shared_ptr>()) + // { + // control_queue_->handle(cmf->GetQueueMessage(200, 0)); + // } read_keys = false; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); diff --git a/src/core/receiver/control_thread.h b/src/core/receiver/control_thread.h index 7d58226e9..a35283ac1 100644 --- a/src/core/receiver/control_thread.h +++ b/src/core/receiver/control_thread.h @@ -35,20 +35,20 @@ #ifndef GNSS_SDR_CONTROL_THREAD_H_ #define GNSS_SDR_CONTROL_THREAD_H_ -#include "agnss_ref_location.h" // for Agnss_Ref_Location -#include "agnss_ref_time.h" // for Agnss_Ref_Time -#include "control_message_factory.h" // for ControlMessage -#include "gnss_sdr_supl_client.h" // for Gnss_Sdr_Supl_Client -#include "tcp_cmd_interface.h" // for TcpCmdInterface -#include // for arma::vec -#include // for boost::thread -#include // for msg_queue, msg_queue::sptr -#include // for time_t -#include // for shared_ptr -#include // for string -#include // for std::thread -#include // for pair -#include // for vector +#include "agnss_ref_location.h" // for Agnss_Ref_Location +#include "agnss_ref_time.h" // for Agnss_Ref_Time +#include "concurrent_queue.h" +#include "gnss_sdr_supl_client.h" // for Gnss_Sdr_Supl_Client +#include "tcp_cmd_interface.h" // for TcpCmdInterface +#include // for arma::vec +#include // for boost::thread +#include +#include // for time_t +#include // for shared_ptr +#include // for string +#include // for std::thread +#include // for pair +#include // for vector class ConfigurationInterface; class GNSSFlowgraph; @@ -97,7 +97,7 @@ public: * * \param[in] boost::shared_ptr control_queue */ - void set_control_queue(const gr::msg_queue::sptr control_queue); // NOLINT(performance-unnecessary-value-param) + void set_control_queue(const std::shared_ptr> control_queue); // NOLINT(performance-unnecessary-value-param) unsigned int processed_control_messages() { @@ -163,9 +163,7 @@ private: void apply_action(unsigned int what); std::shared_ptr flowgraph_; std::shared_ptr configuration_; - gr::msg_queue::sptr control_queue_; - std::shared_ptr control_message_factory_; - std::shared_ptr>> control_messages_; + std::shared_ptr> control_queue_; bool stop_; bool restart_; bool delete_configuration_; diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 7976d99da..f7574a986 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -182,7 +182,7 @@ GNSSBlockFactory::~GNSSBlockFactory() = default; std::unique_ptr GNSSBlockFactory::GetSignalSource( - const std::shared_ptr& configuration, const gr::msg_queue::sptr queue, int ID) // NOLINT(performance-unnecessary-value-param) + const std::shared_ptr& configuration, const std::shared_ptr> queue, int ID) // NOLINT(performance-unnecessary-value-param) { std::string default_implementation = "File_Signal_Source"; std::string role = "SignalSource"; //backwards compatibility for old conf files @@ -321,7 +321,7 @@ std::unique_ptr GNSSBlockFactory::GetPVT(const std::shared_p std::unique_ptr GNSSBlockFactory::GetChannel_1C( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { //"appendix" is added to the "role" with the aim of Acquisition, Tracking and Telemetry Decoder adapters //can find their specific configurations when they read the config @@ -389,7 +389,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1C( std::unique_ptr GNSSBlockFactory::GetChannel_2S( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; @@ -453,7 +453,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_2S( std::unique_ptr GNSSBlockFactory::GetChannel_1B( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -520,7 +520,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1B( std::unique_ptr GNSSBlockFactory::GetChannel_5X( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -587,7 +587,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_5X( std::unique_ptr GNSSBlockFactory::GetChannel_1G( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -655,7 +655,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1G( std::unique_ptr GNSSBlockFactory::GetChannel_2G( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -723,7 +723,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_2G( std::unique_ptr GNSSBlockFactory::GetChannel_L5( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -790,7 +790,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_L5( std::unique_ptr GNSSBlockFactory::GetChannel_B1( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -857,7 +857,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_B1( std::unique_ptr GNSSBlockFactory::GetChannel_B3( const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue) + std::shared_ptr> queue) { std::stringstream stream; stream << channel; @@ -921,7 +921,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_B3( std::unique_ptr>> GNSSBlockFactory::GetChannels( - const std::shared_ptr& configuration, const gr::msg_queue::sptr queue) // NOLINT(performance-unnecessary-value-param) + const std::shared_ptr& configuration, const std::shared_ptr> queue) // NOLINT(performance-unnecessary-value-param) { std::string default_implementation = "Pass_Through"; std::string tracking_implementation; @@ -1241,7 +1241,7 @@ std::unique_ptr GNSSBlockFactory::GetBlock( const std::shared_ptr& configuration, const std::string& role, const std::string& implementation, unsigned int in_streams, - unsigned int out_streams, const gr::msg_queue::sptr queue) // NOLINT(performance-unnecessary-value-param) + unsigned int out_streams, const std::shared_ptr> queue) // NOLINT(performance-unnecessary-value-param) { std::unique_ptr block; diff --git a/src/core/receiver/gnss_block_factory.h b/src/core/receiver/gnss_block_factory.h index 3076c879d..af9889c89 100644 --- a/src/core/receiver/gnss_block_factory.h +++ b/src/core/receiver/gnss_block_factory.h @@ -37,10 +37,11 @@ #ifndef GNSS_SDR_BLOCK_FACTORY_H_ #define GNSS_SDR_BLOCK_FACTORY_H_ -#include // for msg_queue::sptr -#include // for unique_ptr, shared_ptr -#include // for string -#include // for vector +#include "concurrent_queue.h" +#include +#include // for unique_ptr, shared_ptr +#include // for string +#include // for vector class ConfigurationInterface; @@ -59,12 +60,12 @@ public: virtual ~GNSSBlockFactory(); std::unique_ptr GetSignalSource(const std::shared_ptr& configuration, - const gr::msg_queue::sptr queue, int ID = -1); // NOLINT(performance-unnecessary-value-param) + const std::shared_ptr> queue, int ID = -1); // NOLINT(performance-unnecessary-value-param) std::unique_ptr GetSignalConditioner(const std::shared_ptr& configuration, int ID = -1); std::unique_ptr>> GetChannels(const std::shared_ptr& configuration, - const gr::msg_queue::sptr queue); // NOLINT(performance-unnecessary-value-param) + const std::shared_ptr> queue); // NOLINT(performance-unnecessary-value-param) std::unique_ptr GetObservables(const std::shared_ptr& configuration); @@ -76,44 +77,44 @@ public: std::unique_ptr GetBlock(const std::shared_ptr& configuration, const std::string& role, const std::string& implementation, unsigned int in_streams, unsigned int out_streams, - const gr::msg_queue::sptr queue = nullptr); // NOLINT(performance-unnecessary-value-param) + const std::shared_ptr> queue = nullptr); // NOLINT(performance-unnecessary-value-param) private: std::unique_ptr GetChannel_1C(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_2S(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_1B(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_5X(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_L5(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_1G(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_2G(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_B1(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - gr::msg_queue::sptr queue); + std::shared_ptr> queue); std::unique_ptr GetChannel_B3(const std::shared_ptr& configuration, const std::string& acq, const std::string& trk, const std::string& tlm, int channel, - boost::shared_ptr queue); + std::shared_ptr> queue); std::unique_ptr GetAcqBlock( const std::shared_ptr& configuration, diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 5efa45f2b..4488971b7 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -75,7 +75,7 @@ #define GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS 8 -GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr configuration, const gr::msg_queue::sptr queue) // NOLINT(performance-unnecessary-value-param) +GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr configuration, const std::shared_ptr> queue) // NOLINT(performance-unnecessary-value-param) { connected_ = false; running_ = false; @@ -1061,7 +1061,106 @@ bool GNSSFlowgraph::send_telemetry_msg(const pmt::pmt_t& msg) return true; } +void GNSSFlowgraph::push_back_signal(Gnss_Signal gs) +{ + switch (mapStringValues_[gs.get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.remove(gs); + available_GPS_1C_signals_.push_back(gs); + break; + case evGPS_2S: + available_GPS_2S_signals_.remove(gs); + available_GPS_2S_signals_.push_back(gs); + break; + + case evGPS_L5: + available_GPS_L5_signals_.remove(gs); + available_GPS_L5_signals_.push_back(gs); + break; + + case evGAL_1B: + available_GAL_1B_signals_.remove(gs); + available_GAL_1B_signals_.push_back(gs); + break; + + case evGAL_5X: + available_GAL_5X_signals_.remove(gs); + available_GAL_5X_signals_.push_back(gs); + break; + + case evGLO_1G: + available_GLO_1G_signals_.remove(gs); + available_GLO_1G_signals_.push_back(gs); + break; + + case evGLO_2G: + available_GLO_2G_signals_.remove(gs); + available_GLO_2G_signals_.push_back(gs); + break; + + case evBDS_B1: + available_BDS_B1_signals_.remove(gs); + available_BDS_B1_signals_.push_back(gs); + break; + + case evBDS_B3: + available_BDS_B3_signals_.remove(gs); + available_BDS_B3_signals_.push_back(gs); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } +} + +void GNSSFlowgraph::remove_signal(Gnss_Signal gs) +{ + switch (mapStringValues_[gs.get_signal_str()]) + { + case evGPS_1C: + available_GPS_1C_signals_.remove(gs); + break; + + case evGPS_2S: + available_GPS_2S_signals_.remove(gs); + break; + + case evGPS_L5: + available_GPS_L5_signals_.remove(gs); + break; + + case evGAL_1B: + available_GAL_1B_signals_.remove(gs); + break; + + case evGAL_5X: + available_GAL_5X_signals_.remove(gs); + break; + + case evGLO_1G: + available_GLO_1G_signals_.remove(gs); + break; + + case evGLO_2G: + available_GLO_2G_signals_.remove(gs); + break; + + case evBDS_B1: + available_BDS_B1_signals_.remove(gs); + break; + + case evBDS_B3: + available_BDS_B3_signals_.remove(gs); + break; + + default: + LOG(ERROR) << "This should not happen :-("; + break; + } +} /* * Applies an action to the flow graph * @@ -1089,6 +1188,7 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) //todo: the acquisition events are initiated from the acquisition success or failure queued msg. If the acquisition is disabled for non-assisted secondary freq channels, the engine stops.. std::lock_guard lock(signal_list_mutex); + std::cout << "Received " << what << " from " << who << ". acq_channels_count_ = " << acq_channels_count_ << "\n"; DLOG(INFO) << "Received " << what << " from " << who << ". Number of applied actions = " << applied_actions_; unsigned int sat = 0; if (who < 200) @@ -1109,60 +1209,10 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) if (sat == 0) { Gnss_Signal gs = channels_[who]->get_signal(); - switch (mapStringValues_[gs.get_signal_str()]) - { - case evGPS_1C: - available_GPS_1C_signals_.remove(gs); - available_GPS_1C_signals_.push_back(gs); - break; - - case evGPS_2S: - available_GPS_2S_signals_.remove(gs); - available_GPS_2S_signals_.push_back(gs); - break; - - case evGPS_L5: - available_GPS_L5_signals_.remove(gs); - available_GPS_L5_signals_.push_back(gs); - break; - - case evGAL_1B: - available_GAL_1B_signals_.remove(gs); - available_GAL_1B_signals_.push_back(gs); - break; - - case evGAL_5X: - available_GAL_5X_signals_.remove(gs); - available_GAL_5X_signals_.push_back(gs); - break; - - case evGLO_1G: - available_GLO_1G_signals_.remove(gs); - available_GLO_1G_signals_.push_back(gs); - break; - - case evGLO_2G: - available_GLO_2G_signals_.remove(gs); - available_GLO_2G_signals_.push_back(gs); - break; - - case evBDS_B1: - available_BDS_B1_signals_.remove(gs); - available_BDS_B1_signals_.push_back(gs); - break; - - case evBDS_B3: - available_BDS_B3_signals_.remove(gs); - available_BDS_B3_signals_.push_back(gs); - break; - - default: - LOG(ERROR) << "This should not happen :-("; - break; - } + push_back_signal(gs); } channels_state_[who] = 0; - acq_channels_count_--; + if (acq_channels_count_ > 0) acq_channels_count_--; for (unsigned int i = 0; i < channels_count_; i++) { unsigned int ch_index = (who + i + 1) % channels_count_; @@ -1179,19 +1229,27 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) { bool is_primary_freq = true; bool assistance_available = false; + bool start_acquisition = false; + Gnss_Signal gnss_signal; if (sat_ == 0) { float estimated_doppler; double RX_time; - Gnss_Signal gnss_signal; + gnss_signal = search_next_signal(channels_[ch_index]->get_signal().get_signal_str(), false, is_primary_freq, assistance_available, estimated_doppler, RX_time); channels_[ch_index]->set_signal(gnss_signal); + start_acquisition = is_primary_freq or assistance_available; + } + else + { + start_acquisition = true; } //todo: add configuration parameter to enable the mandatory acquisition assistance in secondary freq - if (is_primary_freq == true or assistance_available == true) + if (start_acquisition == true) { channels_state_[ch_index] = 1; acq_channels_count_++; + std::cout << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); #ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); @@ -1203,6 +1261,10 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } else { + push_back_signal(gnss_signal); + //todo: rewrite all + // std::unique_ptr cmf(new ControlMessageFactory()); + // queue_->handle(cmf->GetQueueMessage(i, 0)); DLOG(INFO) << "Channel " << ch_index << " secondary frequency acquisition assistance not available in " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); } } @@ -1214,51 +1276,10 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) LOG(INFO) << "Channel " << who << " ACQ SUCCESS satellite " << channels_[who]->get_signal().get_satellite(); // If the satellite is in the list of available ones, remove it. - switch (mapStringValues_[channels_[who]->get_signal().get_signal_str()]) - { - case evGPS_1C: - available_GPS_1C_signals_.remove(channels_[who]->get_signal()); - break; - - case evGPS_2S: - available_GPS_2S_signals_.remove(channels_[who]->get_signal()); - break; - - case evGPS_L5: - available_GPS_L5_signals_.remove(channels_[who]->get_signal()); - break; - - case evGAL_1B: - available_GAL_1B_signals_.remove(channels_[who]->get_signal()); - break; - - case evGAL_5X: - available_GAL_5X_signals_.remove(channels_[who]->get_signal()); - break; - - case evGLO_1G: - available_GLO_1G_signals_.remove(channels_[who]->get_signal()); - break; - - case evGLO_2G: - available_GLO_2G_signals_.remove(channels_[who]->get_signal()); - break; - - case evBDS_B1: - available_BDS_B1_signals_.remove(channels_[who]->get_signal()); - break; - - case evBDS_B3: - available_BDS_B3_signals_.remove(channels_[who]->get_signal()); - break; - - default: - LOG(ERROR) << "This should not happen :-("; - break; - } + remove_signal(channels_[who]->get_signal()); channels_state_[who] = 2; - acq_channels_count_--; + if (acq_channels_count_ > 0) acq_channels_count_--; for (unsigned int i = 0; i < channels_count_; i++) { unsigned int sat_ = 0; @@ -1274,16 +1295,22 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) { bool is_primary_freq = true; bool assistance_available = false; + bool start_acquisition = false; + Gnss_Signal gnss_signal; if (sat_ == 0) { float estimated_doppler; double RX_time; - Gnss_Signal gnss_signal; gnss_signal = search_next_signal(channels_[i]->get_signal().get_signal_str(), true, is_primary_freq, assistance_available, estimated_doppler, RX_time); + channels_[i]->set_signal(gnss_signal); + } + else + { + start_acquisition = true; } //todo: add configuration parameter to enable the mandatory acquisition assistance in secondary freq - if (is_primary_freq == true or assistance_available == true) + if (start_acquisition == true) { channels_state_[i] = 1; acq_channels_count_++; @@ -1294,11 +1321,17 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) // create a task for the FPGA such that it doesn't stop the flow std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[i]); tmp_thread.detach(); + start_acquisition = is_primary_freq or assistance_available; #endif } else { + push_back_signal(gnss_signal); + //todo: rewrite all + // std::unique_ptr cmf(new ControlMessageFactory()); + // queue_->handle(cmf->GetQueueMessage(i, 0)); DLOG(INFO) << "Channel " << i << " secondary frequency acquisition assistance not available in " << channels_[i]->get_signal().get_satellite() << ", Signal " << channels_[i]->get_signal().get_signal_str(); + std::cout << "Channel " << i << " secondary frequency acquisition assistance not available in " << channels_[i]->get_signal().get_satellite() << ", Signal " << channels_[i]->get_signal().get_signal_str(); } } DLOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; @@ -1328,48 +1361,7 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) LOG(INFO) << "Channel " << who << " Idle state"; if (sat == 0) { - switch (mapStringValues_[channels_[who]->get_signal().get_signal_str()]) - { - case evGPS_1C: - available_GPS_1C_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGPS_2S: - available_GPS_2S_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGPS_L5: - available_GPS_L5_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGAL_1B: - available_GAL_1B_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGAL_5X: - available_GAL_5X_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGLO_1G: - available_GLO_1G_signals_.push_back(channels_[who]->get_signal()); - break; - - case evGLO_2G: - available_GLO_2G_signals_.push_back(channels_[who]->get_signal()); - break; - - case evBDS_B1: - available_BDS_B1_signals_.push_back(channels_[who]->get_signal()); - break; - - case evBDS_B3: - available_BDS_B3_signals_.push_back(channels_[who]->get_signal()); - break; - - default: - LOG(ERROR) << "This should not happen :-("; - break; - } + push_back_signal(channels_[who]->get_signal()); } } break; @@ -1381,57 +1373,8 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) { //recover the satellite assigned Gnss_Signal gs = channels_[n]->get_signal(); - switch (mapStringValues_[gs.get_signal_str()]) - { - case evGPS_1C: - available_GPS_1C_signals_.remove(gs); - available_GPS_1C_signals_.push_back(gs); - break; + push_back_signal(gs); - case evGPS_2S: - available_GPS_2S_signals_.remove(gs); - available_GPS_2S_signals_.push_back(gs); - break; - - case evGPS_L5: - available_GPS_L5_signals_.remove(gs); - available_GPS_L5_signals_.push_back(gs); - break; - - case evGAL_1B: - available_GAL_1B_signals_.remove(gs); - available_GAL_1B_signals_.push_back(gs); - break; - - case evGAL_5X: - available_GAL_5X_signals_.remove(gs); - available_GAL_5X_signals_.push_back(gs); - break; - - case evGLO_1G: - available_GLO_1G_signals_.remove(gs); - available_GLO_1G_signals_.push_back(gs); - break; - - case evGLO_2G: - available_GLO_2G_signals_.remove(gs); - available_GLO_2G_signals_.push_back(gs); - break; - - case evBDS_B1: - available_BDS_B1_signals_.remove(gs); - available_BDS_B1_signals_.push_back(gs); - break; - - case evBDS_B3: - available_BDS_B3_signals_.remove(gs); - available_BDS_B3_signals_.push_back(gs); - break; - - default: - LOG(ERROR) << "This should not happen :-("; - break; - } channels_[n]->stop_channel(); // stop the acquisition or tracking operation channels_state_[n] = 0; } @@ -2071,6 +2014,7 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(const std::string& searched_signal { is_primary_frequency = false; Gnss_Signal result; + bool found_signal = false; switch (mapStringValues_[searched_signal]) { case evGPS_1C: @@ -2090,6 +2034,7 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(const std::string& searched_signal //1. Get the current channel status map std::map> current_channels_status = channels_status_->get_current_status_map(); //2. search the currently tracked GPS L1 satellites and assist the GPS L2 acquisition if the satellite is not tracked on L2 + bool found_signal = false; for (std::map>::iterator it = current_channels_status.begin(); it != current_channels_status.end(); ++it) { if (std::string(it->second->Signal) == "1C") @@ -2107,16 +2052,21 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(const std::string& searched_signal { available_GPS_2S_signals_.erase(it2); } + found_signal = true; + break; } } } //fallback: pick the front satellite because there is no tracked satellites in L1 to assist L2 - result = available_GPS_2S_signals_.front(); - available_GPS_2S_signals_.pop_front(); - if (!pop) + if (found_signal == false) { - available_GPS_2S_signals_.push_back(result); + result = available_GPS_2S_signals_.front(); + available_GPS_2S_signals_.pop_front(); + if (!pop) + { + available_GPS_2S_signals_.push_back(result); + } } } else @@ -2153,19 +2103,14 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(const std::string& searched_signal { available_GPS_L5_signals_.erase(it2); } + found_signal = true; break; } } } - //fallback: pick the front satellite because there is no tracked satellites in L1 to assist L5 - result = available_GPS_L5_signals_.front(); - available_GPS_L5_signals_.pop_front(); - if (!pop) - { - available_GPS_L5_signals_.push_back(result); - } } - else + //fallback: pick the front satellite because there is no tracked satellites in L1 to assist L5 + if (found_signal == false) { result = available_GPS_L5_signals_.front(); available_GPS_L5_signals_.pop_front(); diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index ea2ecc2ad..cfba9914f 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -38,11 +38,11 @@ #define GNSS_SDR_GNSS_FLOWGRAPH_H_ #include "channel_status_msg_receiver.h" +#include "concurrent_queue.h" #include "gnss_sdr_sample_counter.h" #include "gnss_signal.h" #include "pvt_interface.h" #include //for null_sink -#include // for msg_queue, msg_queue::sptr #include // for basic_block_sptr, top_block_sptr #include // for pmt_t #include // for list @@ -72,7 +72,7 @@ public: /*! * \brief Constructor that initializes the receiver flow graph */ - GNSSFlowgraph(std::shared_ptr configuration, const gr::msg_queue::sptr queue); // NOLINT(performance-unnecessary-value-param) + GNSSFlowgraph(std::shared_ptr configuration, const std::shared_ptr> queue); // NOLINT(performance-unnecessary-value-param) /*! * \brief Destructor @@ -108,6 +108,10 @@ public: */ void apply_action(unsigned int who, unsigned int what); + + void push_back_signal(Gnss_Signal gs); + void remove_signal(Gnss_Signal gs); + void set_configuration(std::shared_ptr configuration); unsigned int applied_actions() const @@ -181,7 +185,7 @@ private: gnss_sdr_fpga_sample_counter_sptr ch_out_fpga_sample_counter; #endif gr::top_block_sptr top_block_; - gr::msg_queue::sptr queue_; + std::shared_ptr> queue_; std::list available_GPS_1C_signals_; std::list available_GPS_2S_signals_; diff --git a/src/core/receiver/tcp_cmd_interface.cc b/src/core/receiver/tcp_cmd_interface.cc index 5cac461ad..f274c82dc 100644 --- a/src/core/receiver/tcp_cmd_interface.cc +++ b/src/core/receiver/tcp_cmd_interface.cc @@ -30,7 +30,7 @@ */ #include "tcp_cmd_interface.h" -#include "control_message_factory.h" +#include "command_event.h" #include "pvt_interface.h" #include #include @@ -94,17 +94,16 @@ arma::vec TcpCmdInterface::get_LLH() std::string TcpCmdInterface::reset(const std::vector &commandLine __attribute__((unused))) { std::string response; - std::unique_ptr cmf(new ControlMessageFactory()); if (control_queue_ != nullptr) { - control_queue_->handle(cmf->GetQueueMessage(200, 1)); //send the restart message (who=200,what=1) + command_event_sptr new_evnt = command_event_make(200, 1); //send the restart message (who=200,what=1) + control_queue_->push(pmt::make_any(new_evnt)); response = "OK\n"; } else { response = "ERROR\n"; } - return response; } @@ -112,10 +111,10 @@ std::string TcpCmdInterface::reset(const std::vector &commandLine _ std::string TcpCmdInterface::standby(const std::vector &commandLine __attribute__((unused))) { std::string response; - std::unique_ptr cmf(new ControlMessageFactory()); if (control_queue_ != nullptr) { - control_queue_->handle(cmf->GetQueueMessage(300, 10)); //send the standby message (who=300,what=10) + command_event_sptr new_evnt = command_event_make(300, 10); //send the standby message (who=300,what=10) + control_queue_->push(pmt::make_any(new_evnt)); response = "OK\n"; } else @@ -203,10 +202,10 @@ std::string TcpCmdInterface::hotstart(const std::vector &commandLin } else { - std::unique_ptr cmf(new ControlMessageFactory()); if (control_queue_ != nullptr) { - control_queue_->handle(cmf->GetQueueMessage(300, 12)); //send the standby message (who=300,what=12) + command_event_sptr new_evnt = command_event_make(300, 12); //send the standby message (who=300,what=12) + control_queue_->push(pmt::make_any(new_evnt)); response = "OK\n"; } else @@ -250,10 +249,10 @@ std::string TcpCmdInterface::warmstart(const std::vector &commandLi } else { - std::unique_ptr cmf(new ControlMessageFactory()); if (control_queue_ != nullptr) { - control_queue_->handle(cmf->GetQueueMessage(300, 13)); // send the warmstart message (who=300,what=13) + command_event_sptr new_evnt = command_event_make(300, 13); // send the warmstart message (who=300,what=13) + control_queue_->push(pmt::make_any(new_evnt)); response = "OK\n"; } else @@ -273,16 +272,17 @@ std::string TcpCmdInterface::warmstart(const std::vector &commandLi std::string TcpCmdInterface::coldstart(const std::vector &commandLine __attribute__((unused))) { std::string response; - std::unique_ptr cmf(new ControlMessageFactory()); if (control_queue_ != nullptr) { - control_queue_->handle(cmf->GetQueueMessage(300, 11)); // send the coldstart message (who=300,what=11) + command_event_sptr new_evnt = command_event_make(300, 11); // send the coldstart message (who=300,what=11) + control_queue_->push(pmt::make_any(new_evnt)); response = "OK\n"; } else { response = "ERROR\n"; } + return response; } @@ -296,7 +296,7 @@ std::string TcpCmdInterface::set_ch_satellite(const std::vector &co } -void TcpCmdInterface::set_msg_queue(gr::msg_queue::sptr control_queue) +void TcpCmdInterface::set_msg_queue(std::shared_ptr> control_queue) { control_queue_ = std::move(control_queue); } diff --git a/src/core/receiver/tcp_cmd_interface.h b/src/core/receiver/tcp_cmd_interface.h index e5658a6d9..0b6276e92 100644 --- a/src/core/receiver/tcp_cmd_interface.h +++ b/src/core/receiver/tcp_cmd_interface.h @@ -32,8 +32,9 @@ #define GNSS_SDR_TCP_CMD_INTERFACE_H_ +#include "concurrent_queue.h" #include -#include +#include #include #include #include @@ -50,7 +51,7 @@ public: TcpCmdInterface(); virtual ~TcpCmdInterface(); void run_cmd_server(int tcp_port); - void set_msg_queue(gr::msg_queue::sptr control_queue); + void set_msg_queue(std::shared_ptr> control_queue); /*! * \brief gets the UTC time parsed from the last TC command issued @@ -77,7 +78,7 @@ private: void register_functions(); - gr::msg_queue::sptr control_queue_; + std::shared_ptr> control_queue_; bool keep_running_; time_t receiver_utc_time_; diff --git a/src/tests/data/high_dynamics_signal.bin b/src/tests/data/high_dynamics_signal.bin new file mode 100644 index 0000000000000000000000000000000000000000..ba463e31ca5cdd3c7e18347198476be170129ff2 GIT binary patch literal 168784 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ƲD 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

O#kZ0Wn)(ap$Q(78_l8CJ2H=z#964pX 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 UeW0S~nf2yLxf(ap=*N%$0$=OJ8~^|S literal 0 HcmV?d00001 diff --git a/src/tests/data/high_dynamics_signal.mat b/src/tests/data/high_dynamics_signal.mat new file mode 100644 index 0000000000000000000000000000000000000000..39c1312d595e292abe3f8ed5810e5a785fbcada9 GIT binary patch literal 79823 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 literal 0 HcmV?d00001 diff --git a/src/tests/unit-tests/control-plane/control_message_factory_test.cc b/src/tests/unit-tests/control-plane/control_message_factory_test.cc index 7440d37f4..a2b4448b8 100644 --- a/src/tests/unit-tests/control-plane/control_message_factory_test.cc +++ b/src/tests/unit-tests/control-plane/control_message_factory_test.cc @@ -31,7 +31,6 @@ */ -#include "control_message_factory.h" #include #include diff --git a/src/tests/unit-tests/control-plane/control_thread_test.cc b/src/tests/unit-tests/control-plane/control_thread_test.cc index 781a5af76..2f13cfaa2 100644 --- a/src/tests/unit-tests/control-plane/control_thread_test.cc +++ b/src/tests/unit-tests/control-plane/control_thread_test.cc @@ -32,7 +32,7 @@ #include "control_thread.h" -#include "control_message_factory.h" +#include "concurrent_queue.h" #include "in_memory_configuration.h" #include #include @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -121,7 +120,7 @@ TEST_F(ControlThreadTest /*unused*/, InstantiateRunControlMessages /*unused*/) std::shared_ptr control_thread = std::make_shared(config); - gr::msg_queue::sptr control_queue = gr::msg_queue::make(0); + std::shared_ptr> control_queue = gr::msg_queue::make(0); std::unique_ptr control_msg_factory(new ControlMessageFactory()); @@ -182,7 +181,7 @@ TEST_F(ControlThreadTest /*unused*/, InstantiateRunControlMessages2 /*unused*/) std::unique_ptr control_thread2(new ControlThread(config)); - gr::msg_queue::sptr control_queue2 = gr::msg_queue::make(0); + std::shared_ptr> control_queue2 = gr::msg_queue::make(0); std::unique_ptr control_msg_factory2(new ControlMessageFactory()); @@ -245,7 +244,7 @@ TEST_F(ControlThreadTest /*unused*/, StopReceiverProgrammatically /*unused*/) config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); std::shared_ptr control_thread = std::make_shared(config); - gr::msg_queue::sptr control_queue = gr::msg_queue::make(0); + std::shared_ptr> control_queue = gr::msg_queue::make(0); control_thread->set_control_queue(control_queue); std::thread stop_receiver_thread(stop_receiver); diff --git a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc index 0af18c4e1..c8a427ee6 100644 --- a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc +++ b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc @@ -42,7 +42,7 @@ #include "pvt_interface.h" #include "telemetry_decoder_interface.h" #include "tracking_interface.h" -#include +#include "concurrent_queue.h" #include #include @@ -53,7 +53,7 @@ TEST(GNSSBlockFactoryTest, InstantiateFileSignalSource) std::string path = std::string(TEST_PATH); std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; configuration->set_property("SignalSource.filename", filename); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); // Example of a factory as a shared_ptr std::shared_ptr factory = std::make_shared(); // Example of a block as a shared_ptr @@ -67,7 +67,7 @@ TEST(GNSSBlockFactoryTest, InstantiateWrongSignalSource) { std::shared_ptr configuration = std::make_shared(); configuration->set_property("SignalSource.implementation", "Pepito"); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); // Example of a factory as a unique_ptr std::unique_ptr factory; // Example of a block as a unique_ptr @@ -90,7 +90,7 @@ TEST(GNSSBlockFactoryTest, InstantiateSignalConditioner) TEST(GNSSBlockFactoryTest, InstantiateFIRFilter) { std::shared_ptr configuration = std::make_shared(); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); configuration->set_property("InputFilter.implementation", "Fir_Filter"); @@ -123,7 +123,7 @@ TEST(GNSSBlockFactoryTest, InstantiateFIRFilter) TEST(GNSSBlockFactoryTest, InstantiateFreqXlatingFIRFilter) { std::shared_ptr configuration = std::make_shared(); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); configuration->set_property("InputFilter.implementation", "Freq_Xlating_Fir_Filter"); @@ -158,7 +158,7 @@ TEST(GNSSBlockFactoryTest, InstantiateFreqXlatingFIRFilter) TEST(GNSSBlockFactoryTest, InstantiatePulseBlankingFilter) { std::shared_ptr configuration = std::make_shared(); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); configuration->set_property("InputFilter.implementation", "Pulse_Blanking_Filter"); std::unique_ptr factory; @@ -171,7 +171,7 @@ TEST(GNSSBlockFactoryTest, InstantiatePulseBlankingFilter) TEST(GNSSBlockFactoryTest, InstantiateNotchFilter) { std::shared_ptr configuration = std::make_shared(); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); configuration->set_property("InputFilter.implementation", "Notch_Filter"); std::unique_ptr factory; @@ -184,7 +184,7 @@ TEST(GNSSBlockFactoryTest, InstantiateNotchFilter) TEST(GNSSBlockFactoryTest, InstantiateNotchFilterLite) { std::shared_ptr configuration = std::make_shared(); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); configuration->set_property("InputFilter.implementation", "Notch_Filter_Lite"); std::unique_ptr factory; @@ -309,7 +309,7 @@ TEST(GNSSBlockFactoryTest, InstantiateChannels) configuration->set_property("Channel0.item_type", "gr_complex"); configuration->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Acquisition"); configuration->set_property("Channel1.item_type", "gr_complex"); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); std::unique_ptr factory; std::unique_ptr>> channels = factory->GetChannels(configuration, queue); EXPECT_EQ(static_cast(2), channels->size()); diff --git a/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc b/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc index 711b49d5f..9d26e4477 100644 --- a/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc +++ b/src/tests/unit-tests/control-plane/gnss_flowgraph_test.cc @@ -40,7 +40,7 @@ #include "in_memory_configuration.h" #include "pass_through.h" #include "tracking_interface.h" -#include +#include "concurrent_queue.h" #include diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc index 73e09e9ec..be5a5016a 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc @@ -342,7 +342,7 @@ protected: Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b1i_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b1i_pcps_acquisition_test.cc index c2658889a..e220e5792 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b1i_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b1i_pcps_acquisition_test.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -261,7 +261,7 @@ TEST_F(BeidouB1iPcpsAcquisitionTest, ConnectAndRun) int nsamples = 25000; std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b3i_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b3i_pcps_acquisition_test.cc index 725135d5b..d01343db0 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b3i_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/beidou_b3i_pcps_acquisition_test.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -260,7 +260,7 @@ TEST_F(BeidouB3iPcpsAcquisitionTest, ConnectAndRun) int nsamples = 50000; std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc index a1517dd8f..b63216526 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc @@ -43,7 +43,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -134,7 +134,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr factory; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc index b9c692c4b..ac9244bc2 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc @@ -43,7 +43,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -134,7 +134,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr factory; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc index 591f7bf25..8c0ad9381 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc_test.cc @@ -52,7 +52,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -140,7 +140,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc index 58fa9b8e6..f105841f4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test.cc @@ -47,7 +47,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -265,7 +265,7 @@ TEST_F(GalileoE1PcpsAmbiguousAcquisitionTest, ConnectAndRun) std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); top_block = gr::make_top_block("Acquisition test"); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); init(); std::shared_ptr acq_ = factory->GetBlock(config, "Acquisition_1B", "Galileo_E1_PCPS_Ambiguous_Acquisition", 1, 0); std::shared_ptr acquisition = std::dynamic_pointer_cast(acq_); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc index 60d23b6ba..f757b3edd 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_cccwsr_ambiguous_acquisition_gsoc2013_test.cc @@ -44,7 +44,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -135,7 +135,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr factory; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc index 8c06a3419..dc4058ea8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_quicksync_ambiguous_acquisition_gsoc2014_test.cc @@ -142,7 +142,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr factory; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc index a021e5196..a9af18c8b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_tong_ambiguous_acquisition_gsoc2013_test.cc @@ -44,7 +44,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -135,7 +135,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr factory; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc index 652384472..671350e1b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e5a_pcps_acquisition_gsoc2014_gensource_test.cc @@ -42,7 +42,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -131,7 +131,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc index dbee4f413..8192a3408 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_gsoc2017_test.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -140,7 +140,7 @@ protected: Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; GlonassL1CaPcpsAcquisition* acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc index 86602ec9c..cdaa14cde 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc @@ -41,7 +41,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -184,7 +184,7 @@ TEST_F(GlonassL1CaPcpsAcquisitionTest, ConnectAndRun) int nsamples = 62314; std::chrono::time_point begin, end; std::chrono::duration elapsed_seconds(0); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc index ba0611f90..3cb98fe03 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l2_ca_pcps_acquisition_test.cc @@ -45,7 +45,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -142,7 +142,7 @@ protected: concurrent_queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; GlonassL2CaPcpsAcquisition* acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc index e4ef9974b..ecb757d87 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_gsoc2013_test.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -140,7 +140,7 @@ protected: Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; GpsL1CaPcpsAcquisition* acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc index 0ec417ee0..3134eb558 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -262,7 +262,7 @@ TEST_F(GpsL1CaPcpsAcquisitionTest, ConnectAndRun) int nsamples = 4000; std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); top_block = gr::make_top_block("Acquisition test"); init(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc index 58dd36719..dcc07a9e5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc @@ -41,7 +41,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc index 702b89f31..f20f491d9 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_opencl_acquisition_gsoc2013_test.cc @@ -45,7 +45,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -140,7 +140,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc index 7dfcc5ea1..c8c1847d3 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_quicksync_acquisition_gsoc2014_test.cc @@ -43,7 +43,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -141,7 +141,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr acquisition; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc index b5977ff39..b65748a81 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_tong_acquisition_gsoc2013_test.cc @@ -45,7 +45,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -135,7 +135,7 @@ protected: void stop_queue(); Concurrent_Queue channel_internal_queue; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr acquisition; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc index de7bc4e27..2541d7f75 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc @@ -47,7 +47,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -143,7 +143,7 @@ protected: void init(); void plot_grid(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc index 03d055fac..a662020d5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc @@ -48,7 +48,7 @@ #include "interleaved_byte_to_complex_byte.h" #include "interleaved_short_to_complex_short.h" #include -#include +#include "concurrent_queue.h" #include diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc index 69c1dddf9..8743a11be 100644 --- a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc @@ -46,7 +46,7 @@ #include "in_memory_configuration.h" #include "notch_filter_lite.h" #include -#include +#include "concurrent_queue.h" #include diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc index 8fb783b5f..4b44af6d6 100644 --- a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc @@ -46,7 +46,7 @@ #include "in_memory_configuration.h" #include "notch_filter.h" #include -#include +#include "concurrent_queue.h" #include diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc index d31b971fb..56aa82fd5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc @@ -46,7 +46,7 @@ #include "in_memory_configuration.h" #include "pulse_blanking_filter.h" #include -#include +#include "concurrent_queue.h" #include diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc index 497805de7..0e7774842 100644 --- a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc @@ -30,6 +30,7 @@ * ------------------------------------------------------------------------- */ +#include "hybrid_observables.h" #include "GPS_L1_CA.h" #include "GPS_L2C.h" #include "GPS_L5.h" @@ -51,7 +52,6 @@ #include "gps_l1_ca_pcps_acquisition.h" #include "gps_l2_m_pcps_acquisition.h" #include "gps_l5i_pcps_acquisition.h" -#include "hybrid_observables.h" #include "in_memory_configuration.h" #include "observable_tests_flags.h" #include "observables_dump_reader.h" @@ -707,9 +707,9 @@ void HybridObservablesTest::configure_receiver( std::memcpy(static_cast(gnss_synchro_master.Signal), str, 3); // copy string into synchro char array: 2 char + null config->set_property("Tracking.early_late_space_chips", "0.15"); - config->set_property("Tracking.very_early_late_space_chips", "0.6"); + config->set_property("Tracking.very_early_late_space_chips", "0.5"); config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); - config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); + config->set_property("Tracking.very_early_late_space_narrow_chips", "0.5"); config->set_property("Tracking.track_pilot", "true"); config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); @@ -741,7 +741,8 @@ void HybridObservablesTest::configure_receiver( } config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.track_pilot", "true"); - config->set_property("Tracking.order", "2"); + config->set_property("Tracking.pll_filter_order", "2"); + config->set_property("Tracking.dll_filter_order", "2"); config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); } @@ -755,7 +756,8 @@ void HybridObservablesTest::configure_receiver( config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.track_pilot", "true"); - config->set_property("Tracking.order", "2"); + config->set_property("Tracking.pll_filter_order", "2"); + config->set_property("Tracking.dll_filter_order", "2"); config->set_property("TelemetryDecoder.implementation", "GPS_L5_Telemetry_Decoder"); } @@ -875,78 +877,81 @@ void HybridObservablesTest::check_results_carrier_phase_double_diff( int size2 = measured_ch1.col(0).n_rows; double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); - arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); - //conversion between arma::vec and std:vector - arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); - std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - - - arma::vec true_ch0_carrier_phase_interp; - arma::vec true_ch1_carrier_phase_interp; - arma::interp1(true_tow_ch0_s, true_ch0.col(3), t, true_ch0_carrier_phase_interp); - arma::interp1(true_tow_ch1_s, true_ch1.col(3), t, true_ch1_carrier_phase_interp); - - arma::vec meas_ch0_carrier_phase_interp; - arma::vec meas_ch1_carrier_phase_interp; - arma::interp1(measured_ch0.col(0), measured_ch0.col(3), t, meas_ch0_carrier_phase_interp); - arma::interp1(measured_ch1.col(0), measured_ch1.col(3), t, meas_ch1_carrier_phase_interp); - - // generate double difference accumulated carrier phases - //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) - arma::vec delta_true_carrier_phase_cycles = (true_ch0_carrier_phase_interp - true_ch0_carrier_phase_interp(0)) - (true_ch1_carrier_phase_interp - true_ch1_carrier_phase_interp(0)); - arma::vec delta_measured_carrier_phase_cycles = (meas_ch0_carrier_phase_interp - meas_ch0_carrier_phase_interp(0)) - (meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp(0)); - - //2. RMSE - arma::vec err; - - err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); - - //3. Mean err and variance - double error_mean = arma::mean(err); - double error_var = arma::var(err); - - // 4. Peaks - double max_error = arma::max(err); - double min_error = arma::min(err); - - //5. report - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Double diff Carrier Phase RMSE = " - << rmse << ", mean = " << error_mean - << ", stdev = " << sqrt(error_var) - << " (max,min) = " << max_error - << "," << min_error - << " [Cycles]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) + if ((t1 - t0) > 0) { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Double diff Carrier Phase error [Cycles]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Double diff Carrier Phase error [Cycles]"); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); //conversion between arma::vec and std:vector - std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, range_error_m, - "Double diff Carrier Phase error"); - g3.set_legend(); - g3.savetops(data_title + "double_diff_carrier_phase_error"); + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - g3.showonscreen(); // window output + + arma::vec true_ch0_carrier_phase_interp; + arma::vec true_ch1_carrier_phase_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(3), t, true_ch0_carrier_phase_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(3), t, true_ch1_carrier_phase_interp); + + arma::vec meas_ch0_carrier_phase_interp; + arma::vec meas_ch1_carrier_phase_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(3), t, meas_ch0_carrier_phase_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(3), t, meas_ch1_carrier_phase_interp); + + // generate double difference accumulated carrier phases + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + arma::vec delta_true_carrier_phase_cycles = (true_ch0_carrier_phase_interp - true_ch0_carrier_phase_interp(0)) - (true_ch1_carrier_phase_interp - true_ch1_carrier_phase_interp(0)); + arma::vec delta_measured_carrier_phase_cycles = (meas_ch0_carrier_phase_interp - meas_ch0_carrier_phase_interp(0)) - (meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp(0)); + + //2. RMSE + arma::vec err; + + err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Carrier Phase RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [Cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Carrier Phase error [Cycles]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Carrier Phase error [Cycles]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Carrier Phase error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_carrier_phase_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(rmse, 0.25); + ASSERT_LT(error_mean, 0.2); + ASSERT_GT(error_mean, -0.2); + ASSERT_LT(error_var, 0.5); + ASSERT_LT(max_error, 0.5); + ASSERT_GT(min_error, -0.5); } - - //check results against the test tolerance - ASSERT_LT(rmse, 0.25); - ASSERT_LT(error_mean, 0.2); - ASSERT_GT(error_mean, -0.2); - ASSERT_LT(error_var, 0.5); - ASSERT_LT(max_error, 0.5); - ASSERT_GT(min_error, -0.5); } @@ -966,78 +971,81 @@ void HybridObservablesTest::check_results_carrier_doppler_double_diff( int size2 = measured_ch1.col(0).n_rows; double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); - arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); - //conversion between arma::vec and std:vector - arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); - std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - - - arma::vec true_ch0_carrier_doppler_interp; - arma::vec true_ch1_carrier_doppler_interp; - arma::interp1(true_tow_ch0_s, true_ch0.col(2), t, true_ch0_carrier_doppler_interp); - arma::interp1(true_tow_ch1_s, true_ch1.col(2), t, true_ch1_carrier_doppler_interp); - - arma::vec meas_ch0_carrier_doppler_interp; - arma::vec meas_ch1_carrier_doppler_interp; - arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_carrier_doppler_interp); - arma::interp1(measured_ch1.col(0), measured_ch1.col(2), t, meas_ch1_carrier_doppler_interp); - - // generate double difference carrier Doppler - arma::vec delta_true_carrier_doppler_cycles = true_ch0_carrier_doppler_interp - true_ch1_carrier_doppler_interp; - arma::vec delta_measured_carrier_doppler_cycles = meas_ch0_carrier_doppler_interp - meas_ch1_carrier_doppler_interp; - - //2. RMSE - arma::vec err; - - err = delta_measured_carrier_doppler_cycles - delta_true_carrier_doppler_cycles; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); - - //3. Mean err and variance - double error_mean = arma::mean(err); - double error_var = arma::var(err); - - // 4. Peaks - double max_error = arma::max(err); - double min_error = arma::min(err); - - //5. report - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Double diff Carrier Doppler RMSE = " - << rmse << ", mean = " << error_mean - << ", stdev = " << sqrt(error_var) - << " (max,min) = " << max_error - << "," << min_error - << " [Hz]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) + if ((t1 - t0) > 0) { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Double diff Carrier Doppler error [Hz]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Double diff Carrier Doppler error [Hz]"); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); //conversion between arma::vec and std:vector - std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, range_error_m, - "Double diff Carrier Doppler error"); - g3.set_legend(); - g3.savetops(data_title + "double_diff_carrier_doppler_error"); + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - g3.showonscreen(); // window output + + arma::vec true_ch0_carrier_doppler_interp; + arma::vec true_ch1_carrier_doppler_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(2), t, true_ch0_carrier_doppler_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(2), t, true_ch1_carrier_doppler_interp); + + arma::vec meas_ch0_carrier_doppler_interp; + arma::vec meas_ch1_carrier_doppler_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_carrier_doppler_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(2), t, meas_ch1_carrier_doppler_interp); + + // generate double difference carrier Doppler + arma::vec delta_true_carrier_doppler_cycles = true_ch0_carrier_doppler_interp - true_ch1_carrier_doppler_interp; + arma::vec delta_measured_carrier_doppler_cycles = meas_ch0_carrier_doppler_interp - meas_ch1_carrier_doppler_interp; + + //2. RMSE + arma::vec err; + + err = delta_measured_carrier_doppler_cycles - delta_true_carrier_doppler_cycles; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Carrier Doppler RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(error_mean, 5); + ASSERT_GT(error_mean, -5); + //assuming PLL BW=35 + ASSERT_LT(error_var, 250); + ASSERT_LT(max_error, 100); + ASSERT_GT(min_error, -100); + ASSERT_LT(rmse, 30); } - - //check results against the test tolerance - ASSERT_LT(error_mean, 5); - ASSERT_GT(error_mean, -5); - //assuming PLL BW=35 - ASSERT_LT(error_var, 250); - ASSERT_LT(max_error, 100); - ASSERT_GT(min_error, -100); - ASSERT_LT(rmse, 30); } @@ -1052,71 +1060,75 @@ void HybridObservablesTest::check_results_carrier_doppler( double t0 = measured_ch0(0, 0); int size1 = measured_ch0.col(0).n_rows; double t1 = measured_ch0(size1 - 1, 0); - arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); - //conversion between arma::vec and std:vector - arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); - std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - arma::vec true_ch0_doppler_interp; - arma::interp1(true_tow_s, true_ch0.col(2), t, true_ch0_doppler_interp); - - arma::vec meas_ch0_doppler_interp; - arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_doppler_interp); - - //2. RMSE - arma::vec err_ch0_hz; - - //compute error - err_ch0_hz = meas_ch0_doppler_interp - true_ch0_doppler_interp; - - arma::vec err2_ch0 = arma::square(err_ch0_hz); - double rmse_ch0 = sqrt(arma::mean(err2_ch0)); - - //3. Mean err and variance - double error_mean_ch0 = arma::mean(err_ch0_hz); - double error_var_ch0 = arma::var(err_ch0_hz); - - // 4. Peaks - double max_error_ch0 = arma::max(err_ch0_hz); - double min_error_ch0 = arma::min(err_ch0_hz); - - //5. report - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " - << rmse_ch0 << ", mean = " << error_mean_ch0 - << ", stdev = " << sqrt(error_var_ch0) - << " (max,min) = " << max_error_ch0 - << "," << min_error_ch0 - << " [Hz]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) + if ((t1 - t0) > 0) { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Carrier Doppler error [Hz]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Carrier Doppler error [Hz]"); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); //conversion between arma::vec and std:vector - std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, error_vec, - "Carrier Doppler error"); - g3.set_legend(); - g3.savetops(data_title + "Carrier_doppler_error"); + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - g3.showonscreen(); // window output + arma::vec true_ch0_doppler_interp; + arma::interp1(true_tow_s, true_ch0.col(2), t, true_ch0_doppler_interp); + + arma::vec meas_ch0_doppler_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(2), t, meas_ch0_doppler_interp); + + //2. RMSE + arma::vec err_ch0_hz; + + //compute error + err_ch0_hz = meas_ch0_doppler_interp - true_ch0_doppler_interp; + + arma::vec err2_ch0 = arma::square(err_ch0_hz); + double rmse_ch0 = sqrt(arma::mean(err2_ch0)); + + //3. Mean err and variance + double error_mean_ch0 = arma::mean(err_ch0_hz); + double error_var_ch0 = arma::var(err_ch0_hz); + + // 4. Peaks + double max_error_ch0 = arma::max(err_ch0_hz); + double min_error_ch0 = arma::min(err_ch0_hz); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " + << rmse_ch0 << ", mean = " << error_mean_ch0 + << ", stdev = " << sqrt(error_var_ch0) + << " (max,min) = " << max_error_ch0 + << "," << min_error_ch0 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, error_vec, + "Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "Carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(error_mean_ch0, 5); + ASSERT_GT(error_mean_ch0, -5); + //assuming PLL BW=35 + ASSERT_LT(error_var_ch0, 250); + ASSERT_LT(max_error_ch0, 100); + ASSERT_GT(min_error_ch0, -100); + ASSERT_LT(rmse_ch0, 30); } - - //check results against the test tolerance - ASSERT_LT(error_mean_ch0, 5); - ASSERT_GT(error_mean_ch0, -5); - //assuming PLL BW=35 - ASSERT_LT(error_var_ch0, 250); - ASSERT_LT(max_error_ch0, 100); - ASSERT_GT(min_error_ch0, -100); - ASSERT_LT(rmse_ch0, 30); } void HybridObservablesTest::check_results_duplicated_satellite( @@ -1156,217 +1168,220 @@ void HybridObservablesTest::check_results_duplicated_satellite( t1 = t1_sat1; } - arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); - //conversion between arma::vec and std:vector - arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); - std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - //Doppler - arma::vec meas_sat1_doppler_interp; - arma::interp1(measured_sat1.col(0), measured_sat1.col(2), t, meas_sat1_doppler_interp); - arma::vec meas_sat2_doppler_interp; - arma::interp1(measured_sat2.col(0), measured_sat2.col(2), t, meas_sat2_doppler_interp); - - //Carrier Phase - arma::vec meas_sat1_carrier_phase_interp; - arma::vec meas_sat2_carrier_phase_interp; - arma::interp1(measured_sat1.col(0), measured_sat1.col(3), t, meas_sat1_carrier_phase_interp); - arma::interp1(measured_sat2.col(0), measured_sat2.col(3), t, meas_sat2_carrier_phase_interp); - - // generate double difference accumulated carrier phases - //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) - arma::vec delta_measured_carrier_phase_cycles = (meas_sat1_carrier_phase_interp - meas_sat1_carrier_phase_interp(0)) - (meas_sat2_carrier_phase_interp - meas_sat2_carrier_phase_interp(0)); - - //Pseudoranges - arma::vec meas_sat1_dist_interp; - arma::vec meas_sat2_dist_interp; - arma::interp1(measured_sat1.col(0), measured_sat1.col(4), t, meas_sat1_dist_interp); - arma::interp1(measured_sat2.col(0), measured_sat2.col(4), t, meas_sat2_dist_interp); - // generate delta pseudoranges - arma::vec delta_measured_dist_m = meas_sat1_dist_interp - meas_sat2_dist_interp; - - //Carrier Doppler error - //2. RMSE - arma::vec err_ch0_hz; - - //compute error - err_ch0_hz = meas_sat1_doppler_interp - meas_sat2_doppler_interp; - - //save matlab file for further analysis - std::vector tmp_vector_common_time_s(t.colptr(0), - t.colptr(0) + t.n_rows); - - std::vector tmp_vector_err_ch0_hz(err_ch0_hz.colptr(0), - err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); - save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_ch0_hz, std::string("measured_doppler_error_ch_" + std::to_string(ch_id))); - - //compute statistics - arma::vec err2_ch0 = arma::square(err_ch0_hz); - double rmse_ch0 = sqrt(arma::mean(err2_ch0)); - - //3. Mean err and variance - double error_mean_ch0 = arma::mean(err_ch0_hz); - double error_var_ch0 = arma::var(err_ch0_hz); - - // 4. Peaks - double max_error_ch0 = arma::max(err_ch0_hz); - double min_error_ch0 = arma::min(err_ch0_hz); - - //5. report - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " - << rmse_ch0 << ", mean = " << error_mean_ch0 - << ", stdev = " << sqrt(error_var_ch0) - << " (max,min) = " << max_error_ch0 - << "," << min_error_ch0 - << " [Hz]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) + if ((t1 - t0) > 0) { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Carrier Doppler error [Hz]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Carrier Doppler error [Hz]"); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); //conversion between arma::vec and std:vector - std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, error_vec, - "Carrier Doppler error"); - g3.set_legend(); - g3.savetops(data_title + "Carrier_doppler_error"); + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + //Doppler + arma::vec meas_sat1_doppler_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(2), t, meas_sat1_doppler_interp); + arma::vec meas_sat2_doppler_interp; + arma::interp1(measured_sat2.col(0), measured_sat2.col(2), t, meas_sat2_doppler_interp); - g3.showonscreen(); // window output + //Carrier Phase + arma::vec meas_sat1_carrier_phase_interp; + arma::vec meas_sat2_carrier_phase_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(3), t, meas_sat1_carrier_phase_interp); + arma::interp1(measured_sat2.col(0), measured_sat2.col(3), t, meas_sat2_carrier_phase_interp); + + // generate double difference accumulated carrier phases + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + arma::vec delta_measured_carrier_phase_cycles = (meas_sat1_carrier_phase_interp - meas_sat1_carrier_phase_interp(0)) - (meas_sat2_carrier_phase_interp - meas_sat2_carrier_phase_interp(0)); + + //Pseudoranges + arma::vec meas_sat1_dist_interp; + arma::vec meas_sat2_dist_interp; + arma::interp1(measured_sat1.col(0), measured_sat1.col(4), t, meas_sat1_dist_interp); + arma::interp1(measured_sat2.col(0), measured_sat2.col(4), t, meas_sat2_dist_interp); + // generate delta pseudoranges + arma::vec delta_measured_dist_m = meas_sat1_dist_interp - meas_sat2_dist_interp; + + //Carrier Doppler error + //2. RMSE + arma::vec err_ch0_hz; + + //compute error + err_ch0_hz = meas_sat1_doppler_interp - meas_sat2_doppler_interp; + + //save matlab file for further analysis + std::vector tmp_vector_common_time_s(t.colptr(0), + t.colptr(0) + t.n_rows); + + std::vector tmp_vector_err_ch0_hz(err_ch0_hz.colptr(0), + err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_ch0_hz, std::string("measured_doppler_error_ch_" + std::to_string(ch_id))); + + //compute statistics + arma::vec err2_ch0 = arma::square(err_ch0_hz); + double rmse_ch0 = sqrt(arma::mean(err2_ch0)); + + //3. Mean err and variance + double error_mean_ch0 = arma::mean(err_ch0_hz); + double error_var_ch0 = arma::var(err_ch0_hz); + + // 4. Peaks + double max_error_ch0 = arma::max(err_ch0_hz); + double min_error_ch0 = arma::min(err_ch0_hz); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Doppler RMSE = " + << rmse_ch0 << ", mean = " << error_mean_ch0 + << ", stdev = " << sqrt(error_var_ch0) + << " (max,min) = " << max_error_ch0 + << "," << min_error_ch0 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Doppler error [Hz]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Doppler error [Hz]"); + //conversion between arma::vec and std:vector + std::vector error_vec(err_ch0_hz.colptr(0), err_ch0_hz.colptr(0) + err_ch0_hz.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, error_vec, + "Carrier Doppler error"); + g3.set_legend(); + g3.savetops(data_title + "Carrier_doppler_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(error_mean_ch0, 5); + EXPECT_GT(error_mean_ch0, -5); + //assuming PLL BW=35 + EXPECT_LT(error_var_ch0, 250); + EXPECT_LT(max_error_ch0, 100); + EXPECT_GT(min_error_ch0, -100); + EXPECT_LT(rmse_ch0, 30); + + //Carrier Phase error + //2. RMSE + arma::vec err_carrier_phase; + + err_carrier_phase = delta_measured_carrier_phase_cycles; + + //save matlab file for further analysis + std::vector tmp_vector_err_carrier_phase(err_carrier_phase.colptr(0), + err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_carrier_phase, std::string("measured_carrier_phase_error_ch_" + std::to_string(ch_id))); + + + arma::vec err2_carrier_phase = arma::square(err_carrier_phase); + double rmse_carrier_phase = sqrt(arma::mean(err2_carrier_phase)); + + //3. Mean err and variance + double error_mean_carrier_phase = arma::mean(err_carrier_phase); + double error_var_carrier_phase = arma::var(err_carrier_phase); + + // 4. Peaks + double max_error_carrier_phase = arma::max(err_carrier_phase); + double min_error_carrier_phase = arma::min(err_carrier_phase); + + //5. report + ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Carrier Phase RMSE = " + << rmse_carrier_phase << ", mean = " << error_mean_carrier_phase + << ", stdev = " << sqrt(error_var_carrier_phase) + << " (max,min) = " << max_error_carrier_phase + << "," << min_error_carrier_phase + << " [Cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Carrier Phase error [Cycles]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Carrier Phase error [Cycles]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err_carrier_phase.colptr(0), err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Carrier Phase error"); + g3.set_legend(); + g3.savetops(data_title + "duplicated_satellite_carrier_phase_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(rmse_carrier_phase, 0.25); + EXPECT_LT(error_mean_carrier_phase, 0.2); + EXPECT_GT(error_mean_carrier_phase, -0.2); + EXPECT_LT(error_var_carrier_phase, 0.5); + EXPECT_LT(max_error_carrier_phase, 0.5); + EXPECT_GT(min_error_carrier_phase, -0.5); + + //Pseudorange error + //2. RMSE + arma::vec err_pseudorange; + + err_pseudorange = delta_measured_dist_m; + + //save matlab file for further analysis + std::vector tmp_vector_err_pseudorange(err_pseudorange.colptr(0), + err_pseudorange.colptr(0) + err_pseudorange.n_rows); + save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_pseudorange, std::string("measured_pr_error_ch_" + std::to_string(ch_id))); + + arma::vec err2_pseudorange = arma::square(err_pseudorange); + double rmse_pseudorange = sqrt(arma::mean(err2_pseudorange)); + + //3. Mean err and variance + double error_mean_pseudorange = arma::mean(err_pseudorange); + double error_var_pseudorange = arma::var(err_pseudorange); + + // 4. Peaks + double max_error_pseudorange = arma::max(err_pseudorange); + double min_error_pseudorange = arma::min(err_pseudorange); + + //5. report + ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Pseudorange RMSE = " + << rmse_pseudorange << ", mean = " << error_mean_pseudorange + << ", stdev = " << sqrt(error_var_pseudorange) + << " (max,min) = " << max_error_pseudorange + << "," << min_error_pseudorange + << " [meters]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Pseudorange error [m]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Pseudorange error [m]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err_pseudorange.colptr(0), err_pseudorange.colptr(0) + err_pseudorange.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Pseudorrange error"); + g3.set_legend(); + g3.savetops(data_title + "duplicated_satellite_pseudorrange_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + EXPECT_LT(rmse_pseudorange, 3.0); + EXPECT_LT(error_mean_pseudorange, 1.0); + EXPECT_GT(error_mean_pseudorange, -1.0); + EXPECT_LT(error_var_pseudorange, 10.0); + EXPECT_LT(max_error_pseudorange, 10.0); + EXPECT_GT(min_error_pseudorange, -10.0); } - - //check results against the test tolerance - EXPECT_LT(error_mean_ch0, 5); - EXPECT_GT(error_mean_ch0, -5); - //assuming PLL BW=35 - EXPECT_LT(error_var_ch0, 250); - EXPECT_LT(max_error_ch0, 100); - EXPECT_GT(min_error_ch0, -100); - EXPECT_LT(rmse_ch0, 30); - - //Carrier Phase error - //2. RMSE - arma::vec err_carrier_phase; - - err_carrier_phase = delta_measured_carrier_phase_cycles; - - //save matlab file for further analysis - std::vector tmp_vector_err_carrier_phase(err_carrier_phase.colptr(0), - err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); - save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_carrier_phase, std::string("measured_carrier_phase_error_ch_" + std::to_string(ch_id))); - - - arma::vec err2_carrier_phase = arma::square(err_carrier_phase); - double rmse_carrier_phase = sqrt(arma::mean(err2_carrier_phase)); - - //3. Mean err and variance - double error_mean_carrier_phase = arma::mean(err_carrier_phase); - double error_var_carrier_phase = arma::var(err_carrier_phase); - - // 4. Peaks - double max_error_carrier_phase = arma::max(err_carrier_phase); - double min_error_carrier_phase = arma::min(err_carrier_phase); - - //5. report - ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Carrier Phase RMSE = " - << rmse_carrier_phase << ", mean = " << error_mean_carrier_phase - << ", stdev = " << sqrt(error_var_carrier_phase) - << " (max,min) = " << max_error_carrier_phase - << "," << min_error_carrier_phase - << " [Cycles]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) - { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Carrier Phase error [Cycles]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Carrier Phase error [Cycles]"); - //conversion between arma::vec and std:vector - std::vector range_error_m(err_carrier_phase.colptr(0), err_carrier_phase.colptr(0) + err_carrier_phase.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, range_error_m, - "Carrier Phase error"); - g3.set_legend(); - g3.savetops(data_title + "duplicated_satellite_carrier_phase_error"); - - g3.showonscreen(); // window output - } - - //check results against the test tolerance - EXPECT_LT(rmse_carrier_phase, 0.25); - EXPECT_LT(error_mean_carrier_phase, 0.2); - EXPECT_GT(error_mean_carrier_phase, -0.2); - EXPECT_LT(error_var_carrier_phase, 0.5); - EXPECT_LT(max_error_carrier_phase, 0.5); - EXPECT_GT(min_error_carrier_phase, -0.5); - - //Pseudorange error - //2. RMSE - arma::vec err_pseudorange; - - err_pseudorange = delta_measured_dist_m; - - //save matlab file for further analysis - std::vector tmp_vector_err_pseudorange(err_pseudorange.colptr(0), - err_pseudorange.colptr(0) + err_pseudorange.n_rows); - save_mat_xy(tmp_vector_common_time_s, tmp_vector_err_pseudorange, std::string("measured_pr_error_ch_" + std::to_string(ch_id))); - - arma::vec err2_pseudorange = arma::square(err_pseudorange); - double rmse_pseudorange = sqrt(arma::mean(err2_pseudorange)); - - //3. Mean err and variance - double error_mean_pseudorange = arma::mean(err_pseudorange); - double error_var_pseudorange = arma::var(err_pseudorange); - - // 4. Peaks - double max_error_pseudorange = arma::max(err_pseudorange); - double min_error_pseudorange = arma::min(err_pseudorange); - - //5. report - ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Pseudorange RMSE = " - << rmse_pseudorange << ", mean = " << error_mean_pseudorange - << ", stdev = " << sqrt(error_var_pseudorange) - << " (max,min) = " << max_error_pseudorange - << "," << min_error_pseudorange - << " [meters]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) - { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Pseudorange error [m]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Pseudorange error [m]"); - //conversion between arma::vec and std:vector - std::vector range_error_m(err_pseudorange.colptr(0), err_pseudorange.colptr(0) + err_pseudorange.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, range_error_m, - "Pseudorrange error"); - g3.set_legend(); - g3.savetops(data_title + "duplicated_satellite_pseudorrange_error"); - - g3.showonscreen(); // window output - } - - //check results against the test tolerance - EXPECT_LT(rmse_pseudorange, 3.0); - EXPECT_LT(error_mean_pseudorange, 1.0); - EXPECT_GT(error_mean_pseudorange, -1.0); - EXPECT_LT(error_var_pseudorange, 10.0); - EXPECT_LT(max_error_pseudorange, 10.0); - EXPECT_GT(min_error_pseudorange, -10.0); } bool HybridObservablesTest::save_mat_xy(std::vector& x, std::vector& y, std::string filename) @@ -1420,77 +1435,82 @@ void HybridObservablesTest::check_results_code_pseudorange( int size2 = measured_ch1.col(0).n_rows; double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0)); - arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); - //conversion between arma::vec and std:vector - arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); - std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); - - - arma::vec true_ch0_dist_interp; - arma::vec true_ch1_dist_interp; - arma::interp1(true_tow_ch0_s, true_ch0.col(1), t, true_ch0_dist_interp); - arma::interp1(true_tow_ch1_s, true_ch1.col(1), t, true_ch1_dist_interp); - - arma::vec meas_ch0_dist_interp; - arma::vec meas_ch1_dist_interp; - arma::interp1(measured_ch0.col(0), measured_ch0.col(4), t, meas_ch0_dist_interp); - arma::interp1(measured_ch1.col(0), measured_ch1.col(4), t, meas_ch1_dist_interp); - - // generate delta pseudoranges - arma::vec delta_true_dist_m = true_ch0_dist_interp - true_ch1_dist_interp; - arma::vec delta_measured_dist_m = meas_ch0_dist_interp - meas_ch1_dist_interp; - - //2. RMSE - arma::vec err; - - err = delta_measured_dist_m - delta_true_dist_m; - arma::vec err2 = arma::square(err); - double rmse = sqrt(arma::mean(err2)); - - //3. Mean err and variance - double error_mean = arma::mean(err); - double error_var = arma::var(err); - - // 4. Peaks - double max_error = arma::max(err); - double min_error = arma::min(err); - - //5. report - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(10) << data_title << "Double diff Pseudorange RMSE = " - << rmse << ", mean = " << error_mean - << ", stdev = " << sqrt(error_var) - << " (max,min) = " << max_error - << "," << min_error - << " [meters]" << std::endl; - std::cout.precision(ss); - - //plots - if (FLAGS_show_plots) + if ((t1 - t0) > 0) { - Gnuplot g3("linespoints"); - g3.set_title(data_title + "Double diff Pseudorange error [m]"); - g3.set_grid(); - g3.set_xlabel("Time [s]"); - g3.set_ylabel("Double diff Pseudorange error [m]"); + arma::vec t = arma::linspace(t0, t1, floor((t1 - t0) * 1e3)); //conversion between arma::vec and std:vector - std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); - g3.cmd("set key box opaque"); - g3.plot_xy(time_vector, range_error_m, - "Double diff Pseudorrange error"); - g3.set_legend(); - g3.savetops(data_title + "double_diff_pseudorrange_error"); + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows); + arma::vec true_ch0_dist_interp; + arma::vec true_ch1_dist_interp; + arma::interp1(true_tow_ch0_s, true_ch0.col(1), t, true_ch0_dist_interp); + arma::interp1(true_tow_ch1_s, true_ch1.col(1), t, true_ch1_dist_interp); - g3.showonscreen(); // window output + arma::vec meas_ch0_dist_interp; + arma::vec meas_ch1_dist_interp; + arma::interp1(measured_ch0.col(0), measured_ch0.col(4), t, meas_ch0_dist_interp); + arma::interp1(measured_ch1.col(0), measured_ch1.col(4), t, meas_ch1_dist_interp); + + // generate delta pseudoranges + arma::vec delta_true_dist_m = true_ch0_dist_interp - true_ch1_dist_interp; + arma::vec delta_measured_dist_m = meas_ch0_dist_interp - meas_ch1_dist_interp; + + //2. RMSE + arma::vec err; + + err = delta_measured_dist_m - delta_true_dist_m; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + double error_mean = arma::mean(err); + double error_var = arma::var(err); + + // 4. Peaks + double max_error = arma::max(err); + double min_error = arma::min(err); + + //5. report + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(10) << data_title << "Double diff Pseudorange RMSE = " + << rmse << ", mean = " << error_mean + << ", stdev = " << sqrt(error_var) + << " (max,min) = " << max_error + << "," << min_error + << " [meters]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + Gnuplot g3("linespoints"); + g3.set_title(data_title + "Double diff Pseudorange error [m]"); + g3.set_grid(); + g3.set_xlabel("Time [s]"); + g3.set_ylabel("Double diff Pseudorange error [m]"); + //conversion between arma::vec and std:vector + std::vector range_error_m(err.colptr(0), err.colptr(0) + err.n_rows); + g3.cmd("set key box opaque"); + g3.plot_xy(time_vector, range_error_m, + "Double diff Pseudorrange error"); + g3.set_legend(); + g3.savetops(data_title + "double_diff_pseudorrange_error"); + + g3.showonscreen(); // window output + } + + //check results against the test tolerance + ASSERT_LT(rmse, 3.0); + ASSERT_LT(error_mean, 1.0); + ASSERT_GT(error_mean, -1.0); + ASSERT_LT(error_var, 10.0); + ASSERT_LT(max_error, 10.0); + ASSERT_GT(min_error, -10.0); + } + else + { + std::cout << "Problem with observables in " << data_title << std::endl; } - - //check results against the test tolerance - ASSERT_LT(rmse, 3.0); - ASSERT_LT(error_mean, 1.0); - ASSERT_GT(error_mean, -1.0); - ASSERT_LT(error_var, 10.0); - ASSERT_LT(max_error, 10.0); - ASSERT_GT(min_error, -10.0); } bool HybridObservablesTest::ReadRinexObs(std::vector* obs_vec, Gnss_Synchro gnss) @@ -1981,7 +2001,7 @@ TEST_F(HybridObservablesTest, ValidationOfResults) int sat2_ch_id = -1; for (unsigned int ch = 0; ch < measured_obs_vec.size(); ch++) { - if (epoch_counters_vec.at(ch) > 10) //discard non-valid channels + if (epoch_counters_vec.at(ch) > 100) //discard non-valid channels { if (gnss_synchro_vec.at(ch).PRN == prn_pairs.at(n)) { @@ -2023,7 +2043,7 @@ TEST_F(HybridObservablesTest, ValidationOfResults) unsigned int min_pr_ch_id = 0; for (unsigned int n = 0; n < measured_obs_vec.size(); n++) { - if (epoch_counters_vec.at(n) > 10) //discard non-valid channels + if (epoch_counters_vec.at(n) > 100) //discard non-valid channels { { if (measured_obs_vec.at(n)(0, 4) < min_pr) @@ -2040,8 +2060,20 @@ TEST_F(HybridObservablesTest, ValidationOfResults) } arma::vec receiver_time_offset_ref_channel_s; - receiver_time_offset_ref_channel_s = (true_obs_vec.at(min_pr_ch_id).col(1)(0) - measured_obs_vec.at(min_pr_ch_id).col(4)(0)) / GPS_C_M_S; - std::cout << "Ref. channel initial Receiver time offset " << receiver_time_offset_ref_channel_s(0) * 1e3 << " [ms]" << std::endl; + arma::uvec index2; + index2 = arma::find(true_obs_vec.at(min_pr_ch_id).col(0) >= measured_obs_vec.at(min_pr_ch_id).col(0)(0), 1, "first"); + if ((!index2.empty()) and (index2(0) > 0)) + { + receiver_time_offset_ref_channel_s = (true_obs_vec.at(min_pr_ch_id).col(1)(index2(0)) - measured_obs_vec.at(min_pr_ch_id).col(4)(0)) / GPS_C_M_S; + std::cout << "Ref. channel initial Receiver time offset " << receiver_time_offset_ref_channel_s(0) * 1e3 << " [ms]" << std::endl; + } + else + { + ASSERT_NO_THROW( + throw std::exception();) + << "Error finding observation time epoch in the reference data"; + } + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) { @@ -2083,7 +2115,7 @@ TEST_F(HybridObservablesTest, ValidationOfResults) save_mat_xy(tmp_vector_x6, tmp_vector_y6, std::string("measured_cp_ch_" + std::to_string(n))); - if (epoch_counters_vec.at(n) > 10) //discard non-valid channels + if (epoch_counters_vec.at(n) > 100) //discard non-valid channels { arma::vec true_TOW_ref_ch_s = true_obs_vec.at(min_pr_ch_id).col(0) - receiver_time_offset_ref_channel_s(0); arma::vec true_TOW_ch_s = true_obs_vec.at(n).col(0) - receiver_time_offset_ref_channel_s(0); @@ -2097,7 +2129,6 @@ TEST_F(HybridObservablesTest, ValidationOfResults) measured_obs_vec.at(n), measured_obs_vec.at(min_pr_ch_id), "[CH " + std::to_string(n) + "] PRN " + std::to_string(gnss_synchro_vec.at(n).PRN) + " "); - //Do not compare E5a with E5 RINEX due to the Doppler frequency discrepancy caused by the different center frequencies //E5a_fc=1176.45e6, E5b_fc=1207.14e6, E5_fc=1191.795e6; if (strcmp("5X\0", gnss_synchro_vec.at(n).Signal) != 0 or FLAGS_compare_with_5X) diff --git a/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc b/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc index d8ce67450..553637df8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc @@ -42,7 +42,7 @@ #include "direct_resampler_conditioner_cc.h" #include "gnss_sdr_valve.h" #include -#include +#include "concurrent_queue.h" TEST(DirectResamplerConditionerCcTest, InstantiationAndRunTest) @@ -52,7 +52,7 @@ TEST(DirectResamplerConditionerCcTest, InstantiationAndRunTest) std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); int nsamples = 1000000; //Number of samples to be computed - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); gr::top_block_sptr top_block = gr::make_top_block("direct_resampler_conditioner_cc_test"); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); diff --git a/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc b/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc index 2bc26b8b4..571230f03 100644 --- a/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/resampler/mmse_resampler_test.cc @@ -40,7 +40,7 @@ #include "gnss_sdr_valve.h" #include "mmse_resampler_conditioner.h" #include -#include +#include "concurrent_queue.h" TEST(MmseResamplerTest, InstantiationAndRunTestWarning) { @@ -49,7 +49,7 @@ TEST(MmseResamplerTest, InstantiationAndRunTestWarning) std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); int nsamples = 1000000; //Number of samples to be computed - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); gr::top_block_sptr top_block = gr::make_top_block("mmse_resampler_conditioner_cc_test"); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); @@ -90,7 +90,7 @@ TEST(MmseResamplerTest, InstantiationAndRunTest2) std::chrono::time_point start, end; std::chrono::duration elapsed_seconds(0); int nsamples = 1000000; //Number of samples to be computed - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); gr::top_block_sptr top_block = gr::make_top_block("mmse_resampler_conditioner_cc_test"); boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); diff --git a/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc b/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc index dd1020249..bc7eb5acb 100644 --- a/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc @@ -31,7 +31,7 @@ #include "file_signal_source.h" #include "in_memory_configuration.h" -#include +#include "concurrent_queue.h" #include #include #include diff --git a/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc b/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc index 02e1b09df..4c460b63f 100644 --- a/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/sources/gnss_sdr_valve_test.cc @@ -40,11 +40,11 @@ #endif #include "gnss_sdr_valve.h" #include -#include +#include "concurrent_queue.h" TEST(ValveTest, CheckEventSentAfter100Samples) { - gr::msg_queue::sptr queue = gr::msg_queue::make(0); + std::shared_ptr> queue = gr::msg_queue::make(0); gr::top_block_sptr top_block = gr::make_top_block("gnss_sdr_valve_test"); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc index 469ec2c27..bf78395bf 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e1_dll_pll_veml_tracking_test.cc @@ -41,7 +41,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -68,7 +68,7 @@ protected: void init(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc index 122184eb7..6c4b8e0ef 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/galileo_e5a_tracking_test.cc @@ -41,7 +41,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -69,7 +69,7 @@ protected: void init(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc index 003c63a9d..1fa07acc4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_c_aid_tracking_test.cc @@ -42,7 +42,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -119,7 +119,7 @@ protected: void init(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc index 20a910ce4..207217937 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/glonass_l1_ca_dll_pll_tracking_test.cc @@ -42,7 +42,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -120,7 +120,7 @@ protected: void init(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc index a640db425..59a63480e 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc @@ -42,7 +42,7 @@ #include #include #include -#include +#include "concurrent_queue.h" #include #include #include @@ -123,7 +123,7 @@ protected: void init(); - gr::msg_queue::sptr queue; + std::shared_ptr> queue; gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc index fb38b8efa..9b9e04baf 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc @@ -36,7 +36,7 @@ #include "Galileo_E1.h" #include "Galileo_E5a.h" #include "acquisition_msg_rx.h" -#include "control_message_factory.h" +#include "concurrent_queue.h" #include "galileo_e1_pcps_ambiguous_acquisition.h" #include "galileo_e5a_noncoherent_iq_acquisition_caf.h" #include "galileo_e5a_pcps_acquisition.h" @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include @@ -229,7 +228,7 @@ public: Gnss_Synchro gnss_synchro; size_t item_size; - gr::msg_queue::sptr queue; + std::shared_ptr> queue; }; diff --git a/src/utils/front-end-cal/main.cc b/src/utils/front-end-cal/main.cc index 54723dfc5..e5f8e8520 100644 --- a/src/utils/front-end-cal/main.cc +++ b/src/utils/front-end-cal/main.cc @@ -62,7 +62,7 @@ #include #include // for gr_complex #include // for io_signature -#include +#include "concurrent_queue.h" #include // for block_sptr #include #include // for pmt_t, to_long