From 268fc1215cdb317f992d5a54bb8aa52c7c4576a3 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 22 Jan 2021 17:32:37 +0100 Subject: [PATCH 01/12] Refactor private implementation of flowgraph connection and disconnection --- src/core/receiver/gnss_flowgraph.cc | 2020 ++++++++++++++++----------- src/core/receiver/gnss_flowgraph.h | 46 +- 2 files changed, 1222 insertions(+), 844 deletions(-) diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index a39849b4c..1566f3616 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -57,7 +57,6 @@ #include // for std::thread #include // for std::move - #ifdef GR_GREATER_38 #include #else @@ -89,6 +88,168 @@ GNSSFlowgraph::~GNSSFlowgraph() } +void GNSSFlowgraph::init() +{ + /* + * Instantiates the receiver blocks + */ + auto block_factory = std::make_unique(); + + channels_status_ = channel_status_msg_receiver_make(); + + // 1. read the number of RF front-ends available (one file_source per RF front-end) + sources_count_ = configuration_->property("Receiver.sources_count", 1); + + int RF_Channels = 0; + int signal_conditioner_ID = 0; + + if (sources_count_ > 1) + { + for (int i = 0; i < sources_count_; i++) + { + std::cout << "Creating source " << i << '\n'; + sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), i)); + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + std::cout << "RF Channels " << RF_Channels << '\n'; + for (int j = 0; j < RF_Channels; j++) + { + sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); + signal_conditioner_ID++; + } + } + } + else + { + // backwards compatibility for old config files + sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), -1)); + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); + if (RF_Channels != 0) + { + for (int j = 0; j < RF_Channels; j++) + { + sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); + signal_conditioner_ID++; + } + } + else + { + // old config file, single signal source and single channel, not specified + sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), -1)); + } + } + + signal_conditioner_connected_ = std::vector(sig_conditioner_.size(), false); + + observables_ = block_factory->GetObservables(configuration_.get()); + + pvt_ = block_factory->GetPVT(configuration_.get()); + + auto channels = block_factory->GetChannels(configuration_.get(), queue_.get()); + + channels_count_ = static_cast(channels->size()); + for (int i = 0; i < channels_count_; i++) + { + std::shared_ptr chan_ = std::move(channels->at(i)); + channels_.push_back(std::dynamic_pointer_cast(chan_)); + } + + top_block_ = gr::make_top_block("GNSSFlowgraph"); + + mapStringValues_["1C"] = evGPS_1C; + mapStringValues_["2S"] = evGPS_2S; + mapStringValues_["L5"] = evGPS_L5; + mapStringValues_["1B"] = evGAL_1B; + mapStringValues_["5X"] = evGAL_5X; + mapStringValues_["7X"] = evGAL_7X; + mapStringValues_["E6"] = evGAL_E6; + mapStringValues_["1G"] = evGLO_1G; + mapStringValues_["2G"] = evGLO_2G; + mapStringValues_["B1"] = evBDS_B1; + mapStringValues_["B3"] = evBDS_B3; + + // fill the signals queue with the satellites ID's to be searched by the acquisition + set_signals_list(); + set_channels_state(); + DLOG(INFO) << "Blocks instantiated. " << channels_count_ << " channels."; + + /* + * Instantiate the receiver monitor block, if required + */ + enable_monitor_ = configuration_->property("Monitor.enable_monitor", false); + if (enable_monitor_) + { + // Retrieve monitor properties + bool enable_protobuf = configuration_->property("Monitor.enable_protobuf", true); + if (configuration_->property("PVT.enable_protobuf", false) == true) + { + enable_protobuf = true; + } + std::string address_string = configuration_->property("Monitor.client_addresses", std::string("127.0.0.1")); + std::vector udp_addr_vec = split_string(address_string, '_'); + std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); + udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + + // Instantiate monitor object + GnssSynchroMonitor_ = gnss_synchro_make_monitor(channels_count_, + configuration_->property("Monitor.decimation_factor", 1), + configuration_->property("Monitor.udp_port", 1234), + udp_addr_vec, enable_protobuf); + } + + /* + * Instantiate the receiver acquisition monitor block, if required + */ + enable_acquisition_monitor_ = configuration_->property("AcquisitionMonitor.enable_monitor", false); + if (enable_acquisition_monitor_) + { + // Retrieve monitor properties + bool enable_protobuf = configuration_->property("AcquisitionMonitor.enable_protobuf", true); + if (configuration_->property("PVT.enable_protobuf", false) == true) + { + enable_protobuf = true; + } + std::string address_string = configuration_->property("AcquisitionMonitor.client_addresses", std::string("127.0.0.1")); + std::vector udp_addr_vec = split_string(address_string, '_'); + std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); + udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + + GnssSynchroAcquisitionMonitor_ = gnss_synchro_make_monitor(channels_count_, + configuration_->property("AcquisitionMonitor.decimation_factor", 1), + configuration_->property("AcquisitionMonitor.udp_port", 1235), + udp_addr_vec, enable_protobuf); + } + + /* + * Instantiate the receiver tracking monitor block, if required + */ + enable_tracking_monitor_ = configuration_->property("TrackingMonitor.enable_monitor", false); + if (enable_tracking_monitor_) + { + // Retrieve monitor properties + bool enable_protobuf = configuration_->property("TrackingMonitor.enable_protobuf", true); + if (configuration_->property("PVT.enable_protobuf", false) == true) + { + enable_protobuf = true; + } + std::string address_string = configuration_->property("TrackingMonitor.client_addresses", std::string("127.0.0.1")); + std::vector udp_addr_vec = split_string(address_string, '_'); + std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); + udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + + GnssSynchroTrackingMonitor_ = gnss_synchro_make_monitor(channels_count_, + configuration_->property("TrackingMonitor.decimation_factor", 1), + configuration_->property("TrackingMonitor.udp_port", 1236), + udp_addr_vec, enable_protobuf); + } +} + + void GNSSFlowgraph::start() { if (running_) @@ -103,12 +264,11 @@ void GNSSFlowgraph::start() } catch (const std::exception& e) { - LOG(WARNING) << "Unable to start flowgraph"; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Unable to start flowgraph: " << e.what(); return; } -#ifdef ENABLE_FPGA +#if ENABLE_FPGA // start the DMA if the receiver is in post-processing mode if (configuration_->property(sig_source_.at(0)->role() + ".switch_position", 0) == 0) { @@ -127,18 +287,30 @@ void GNSSFlowgraph::stop() chan->stop_channel(); // stop the acquisition or tracking operation } top_block_->stop(); -#ifndef ENABLE_FPGA +#if ENABLE_FPGA +#else top_block_->wait(); #endif running_ = false; } +void GNSSFlowgraph::wait() +{ + if (!running_) + { + LOG(WARNING) << "Can't apply wait. Flowgraph is not running"; + return; + } + top_block_->wait(); + DLOG(INFO) << "Flowgraph finished calculations"; + running_ = false; +} + + void GNSSFlowgraph::connect() { // Connects the blocks in the flow graph - // Signal Source > Signal conditioner >> Channels >> Observables >> PVT - LOG(INFO) << "Connecting flowgraph"; if (connected_) { @@ -146,44 +318,379 @@ void GNSSFlowgraph::connect() return; } -#ifndef ENABLE_FPGA - for (int i = 0; i < sources_count_; i++) +#if ENABLE_FPGA + if (connect_fpga_flowgraph() != 0) { - if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) + return; + } +#else + if (connect_desktop_flowgraph() != 0) + { + return; + } +#endif + + connected_ = true; + LOG(INFO) << "Flowgraph connected"; + top_block_->dump(); +} + + +void GNSSFlowgraph::disconnect() +{ + LOG(INFO) << "Disconnecting flowgraph"; + + if (!connected_) + { + LOG(INFO) << "flowgraph was not connected"; + return; + } + connected_ = false; + +#if ENABLE_FPGA + if (disconnect_fpga_flowgraph() != 0) + { + return; + } +#else + if (disconnect_desktop_flowgraph() != 0) + { + return; + } +#endif + + LOG(INFO) << "Flowgraph disconnected"; +} + + +int GNSSFlowgraph::connect_desktop_flowgraph() +{ +#if ENABLE_FPGA + return 0; +#else + // Connect blocks to the top_block + if (connect_signal_sources() != 0) + { + return 1; + } + + if (connect_signal_conditioners() != 0) + { + return 1; + } + + if (connect_channels() != 0) + { + return 1; + } + + if (connect_observables() != 0) + { + return 1; + } + + if (connect_pvt() != 0) + { + return 1; + } + + // Connect blocks between them to form the flow graph + if (connect_signal_sources_to_signal_conditioners() != 0) + { + return 1; + } + + if (connect_sample_counter() != 0) + { + return 1; + } + + if (connect_signal_conditioners_to_channels() != 0) + { + return 1; + } + + if (connect_channels_to_observables() != 0) + { + return 1; + } + + check_signal_conditioners(); + + assign_channels(); + + if (connect_observables_to_pvt() != 0) + { + return 1; + } + + if (connect_monitors() != 0) + { + return 1; + } + + // Activate acquisition in enabled channels + for (int i = 0; i < channels_count_; i++) + { + LOG(INFO) << "Channel " << i << " assigned to " << channels_.at(i)->get_signal(); + if (channels_state_[i] == 1) { - try - { - sig_source_.at(i)->connect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't connect signal source block " << i << " internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + channels_.at(i)->start_acquisition(); + LOG(INFO) << "Channel " << i << " connected to observables and ready for acquisition"; + } + else + { + LOG(INFO) << "Channel " << i << " connected to observables in standby mode"; } } - // Signal Source > Signal conditioner > - for (auto& sig : sig_conditioner_) + LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration has been successfully connected"; + return 0; +#endif +} + + +int GNSSFlowgraph::disconnect_desktop_flowgraph() +{ +#if ENABLE_FPGA + return 0; +#else + // Disconnect blocks between them + if (disconnect_signal_sources_from_signal_conditioners() != 0) { - if (configuration_->property(sig->role() + ".enable_FPGA", false) == false) + return 1; + } + + if (disconnect_sample_counter() != 0) + { + return 1; + } + + if (disconnect_signal_conditioners_from_channels() != 0) + { + return 1; + } + + if (disconnect_channels_from_observables() != 0) + { + return 1; + } + + if (disconnect_monitors() != 0) + { + return 1; + } + + if (disconnect_observables_from_pvt() != 0) + { + return 1; + } + + // Disconnect blocks from the top_block + if (disconnect_signal_sources() != 0) + { + return 1; + } + + if (disconnect_signal_conditioners() != 0) + { + return 1; + } + + if (disconnect_channels() != 0) + { + return 1; + } + + if (disconnect_observables() != 0) + { + return 1; + } + + if (disconnect_pvt() != 0) + { + return 1; + } + + return 0; +#endif +} + + +#if ENABLE_FPGA +int GNSSFlowgraph::connect_fpga_flowgraph() +{ + // Connect blocks to the top_block + if (connect_channels() != 0) + { + return 1; + } + + if (connect_observables() != 0) + { + return 1; + } + + if (connect_pvt() != 0) + { + return 1; + } + + DLOG(INFO) << "Blocks connected internally to the top_block"; + + // Connect the counter + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + { + if (connect_sample_counter() != 0) { - try - { - sig->connect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't connect signal conditioner block internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + return 1; } } + else + { + if (connect_fpga_sample_counter() != 0) + { + return 1; + } + } + + if (connect_channels_to_observables() != 0) + { + return 1; + } + + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + { + check_signal_conditioners(); + } + + assign_channels(); + + if (connect_observables_to_pvt() != 0) + { + return 1; + } + + if (connect_monitors() != 0) + { + return 1; + } + LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration with FPGA off-loading has been successfully connected"; + return 0; +} + + +int GNSSFlowgraph::disconnect_fpga_flowgraph() +{ + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + { + if (disconnect_signal_sources_from_signal_conditioners() != 0) + { + return 1; + } + } + + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + { + if (disconnect_sample_counter() != 0) + { + return 1; + } + } + else + { + if (disconnect_fpga_sample_counter() != 0) + { + return 1; + } + } + + if (disconnect_monitors() != 0) + { + return 1; + } + + if (disconnect_channels_from_observables() != 0) + { + return 1; + } + + if (disconnect_observables_from_pvt() != 0) + { + return 1; + } + + if (disconnect_signal_sources() != 0) + { + return 1; + } + + if (disconnect_signal_conditioners() != 0) + { + return 1; + } + + if (disconnect_channels() != 0) + { + return 1; + } + + if (disconnect_observables() != 0) + { + return 1; + } + + if (disconnect_pvt() != 0) + { + return 1; + } + + return 0; +} #endif + + +int GNSSFlowgraph::connect_signal_sources() +{ + for (int i = 0; i < sources_count_; i++) + { + try + { + sig_source_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect signal source block " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + DLOG(INFO) << "Signal Source blocks successfully connected to the top_block"; + return 0; +} + + +int GNSSFlowgraph::disconnect_signal_sources() +{ + for (int i = 0; i < sources_count_; i++) + { + try + { + sig_source_.at(i)->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source block " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + +int GNSSFlowgraph::connect_channels() +{ for (int i = 0; i < channels_count_; i++) { try @@ -192,41 +699,194 @@ void GNSSFlowgraph::connect() } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect channel " << i << " internally"; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Can't connect channel " << i << " internally: " << e.what(); top_block_->disconnect_all(); - return; + return 1; } } + DLOG(INFO) << "Channel blocks successfully connected to the top_block"; + return 0; +} + +int GNSSFlowgraph::disconnect_channels() +{ + for (int i = 0; i < channels_count_; i++) + { + try + { + channels_.at(i)->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect channel " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + +int GNSSFlowgraph::connect_observables() +{ try { observables_->connect(top_block_); } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect observables block internally"; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Can't connect observables block internally: " << e.what(); top_block_->disconnect_all(); - return; + return 1; } + DLOG(INFO) << "Observables block successfully connected to the top_block"; + return 0; +} - // Signal Source > Signal conditioner >> Channels >> Observables > PVT + +int GNSSFlowgraph::disconnect_observables() +{ + try + { + observables_->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect observables block internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} + + +int GNSSFlowgraph::connect_pvt() +{ try { pvt_->connect(top_block_); } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect PVT block internally"; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Can't connect PVT block internally: " << e.what(); top_block_->disconnect_all(); - return; + return 1; } + DLOG(INFO) << "PVT block successfully connected to the top_block"; + return 0; +} - DLOG(INFO) << "blocks connected internally"; -// Signal Source (i) > Signal conditioner (i) > -#ifndef ENABLE_FPGA + +int GNSSFlowgraph::disconnect_pvt() +{ + try + { + pvt_->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect PVT block internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} + + +int GNSSFlowgraph::connect_sample_counter() +{ + // connect the sample counter to the Signal Conditioner + // connect the sample counter to Observables + try + { + const double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file\n"; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } + + const int observable_interval_ms = configuration_->property("GNSS-SDR.observable_interval_ms", 20); + ch_out_sample_counter_ = gnss_sdr_make_sample_counter(fs, observable_interval_ms, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); + top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); + top_block_->connect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect sample counter: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "sample counter successfully connected to Signal Conditioner and Observables blocks"; + return 0; +} + + +int GNSSFlowgraph::disconnect_sample_counter() +{ + try + { + top_block_->disconnect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); + top_block_->disconnect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect sample counter: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} + +#if ENABLE_FPGA +int GNSSFlowgraph::connect_fpga_sample_counter() +{ + // create a hardware-defined gnss_synchro pulse for the observables block + try + { + const double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file\n"; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } + const int observable_interval_ms = configuration_->property("GNSS-SDR.observable_interval_ms", 20); + ch_out_fpga_sample_counter_ = gnss_sdr_make_fpga_sample_counter(fs, observable_interval_ms); + top_block_->connect(ch_out_fpga_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect FPGA sample counter: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + LOG(INFO) << "FPGA sample counter successfully connected"; + return 0; +} + + +int GNSSFlowgraph::disconnect_fpga_sample_counter() +{ + try + { + top_block_->disconnect(ch_out_fpga_sample_counter_, 0, observables_->get_left_block(), channels_count_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect FPGA sample counter: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} +#endif + + +int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() +{ int RF_Channels = 0; unsigned int signal_conditioner_ID = 0; for (int i = 0; i < sources_count_; i++) @@ -288,241 +948,196 @@ void GNSSFlowgraph::connect() } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Can't connect signal source " << i << " to signal conditioner " << i << ": " << e.what(); top_block_->disconnect_all(); - return; + return 1; } } - DLOG(INFO) << "Signal source connected to signal conditioner"; -#endif -#if ENABLE_FPGA - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) - { - // connect the signal source to sample counter - // connect the sample counter to Observables - try - { - const double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); - if (fs == 0.0) - { - LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; - std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file\n"; - throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); - } - const int observable_interval_ms = configuration_->property("GNSS-SDR.observable_interval_ms", 20); - ch_out_sample_counter_ = gnss_sdr_make_sample_counter(fs, observable_interval_ms, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); - top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); - top_block_->connect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } - else - { - // create a hardware-defined gnss_synchro pulse for the observables block - try - { - const double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); - if (fs == 0.0) - { - LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; - std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file\n"; - throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); - } - const int observable_interval_ms = configuration_->property("GNSS-SDR.observable_interval_ms", 20); - ch_out_fpga_sample_counter_ = gnss_sdr_make_fpga_sample_counter(fs, observable_interval_ms); - top_block_->connect(ch_out_fpga_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect FPGA sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } -#else - // connect the signal source to sample counter - // connect the sample counter to Observables - try - { - const double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); - if (fs == 0.0) - { - LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; - std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file\n"; - throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); - } + DLOG(INFO) << "Signal source(s) successfully connected to signal conditioner(s)"; + return 0; +} - const int observable_interval_ms = configuration_->property("GNSS-SDR.observable_interval_ms", 20); - ch_out_sample_counter_ = gnss_sdr_make_sample_counter(fs, observable_interval_ms, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); - top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); - top_block_->connect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } -#endif - // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) - std::vector signal_conditioner_connected; - signal_conditioner_connected.reserve(sig_conditioner_.size()); - for (size_t n = 0; n < sig_conditioner_.size(); n++) - { - signal_conditioner_connected.push_back(false); - } +int GNSSFlowgraph::connect_signal_conditioners_to_channels() +{ for (int i = 0; i < channels_count_; i++) { -#ifndef ENABLE_FPGA int selected_signal_conditioner_ID = 0; const bool use_acq_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); const uint32_t fs = configuration_->property("GNSS-SDR.internal_fs_sps", 0); - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + + try { - try + selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + } + try + { + // Enable automatic resampler for the acquisition, if required + if (use_acq_resampler == true) { - selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); - } - catch (const std::exception& e) - { - LOG(WARNING) << e.what(); - } - try - { - // Enable automatic resampler for the acquisition, if required - if (use_acq_resampler == true) + // create acquisition resamplers if required + double resampler_ratio = 1.0; + double acq_fs = fs; + // find the signal associated to this channel + switch (mapStringValues_[channels_.at(i)->get_signal().get_signal_str()]) { - // create acquisition resamplers if required - double resampler_ratio = 1.0; - double acq_fs = fs; - // find the signal associated to this channel - switch (mapStringValues_[channels_.at(i)->get_signal().get_signal_str()]) + case evGPS_1C: + acq_fs = GPS_L1_CA_OPT_ACQ_FS_SPS; + break; + case evGPS_2S: + acq_fs = GPS_L2C_OPT_ACQ_FS_SPS; + break; + case evGPS_L5: + acq_fs = GPS_L5_OPT_ACQ_FS_SPS; + break; + case evSBAS_1C: + acq_fs = GPS_L1_CA_OPT_ACQ_FS_SPS; + break; + case evGAL_1B: + acq_fs = GALILEO_E1_OPT_ACQ_FS_SPS; + break; + case evGAL_5X: + acq_fs = GALILEO_E5A_OPT_ACQ_FS_SPS; + break; + case evGAL_7X: + acq_fs = GALILEO_E5B_OPT_ACQ_FS_SPS; + break; + case evGAL_E6: + acq_fs = GALILEO_E6_OPT_ACQ_FS_SPS; + break; + case evGLO_1G: + case evGLO_2G: + case evBDS_B1: + case evBDS_B3: + acq_fs = fs; + break; + default: + break; + } + + if (acq_fs < fs) + { + // check if the resampler is already created for the channel system/signal and for the specific RF Channel + const std::string map_key = channels_.at(i)->get_signal().get_signal_str() + std::to_string(selected_signal_conditioner_ID); + resampler_ratio = static_cast(fs) / acq_fs; + int decimation = floor(resampler_ratio); + while (fs % decimation > 0) { - case evGPS_1C: - acq_fs = GPS_L1_CA_OPT_ACQ_FS_SPS; - break; - case evGPS_2S: - acq_fs = GPS_L2C_OPT_ACQ_FS_SPS; - break; - case evGPS_L5: - acq_fs = GPS_L5_OPT_ACQ_FS_SPS; - break; - case evSBAS_1C: - acq_fs = GPS_L1_CA_OPT_ACQ_FS_SPS; - break; - case evGAL_1B: - acq_fs = GALILEO_E1_OPT_ACQ_FS_SPS; - break; - case evGAL_5X: - acq_fs = GALILEO_E5A_OPT_ACQ_FS_SPS; - break; - case evGAL_7X: - acq_fs = GALILEO_E5B_OPT_ACQ_FS_SPS; - break; - case evGAL_E6: - acq_fs = GALILEO_E6_OPT_ACQ_FS_SPS; - break; - case evGLO_1G: - case evGLO_2G: - case evBDS_B1: - case evBDS_B3: - acq_fs = fs; - break; - default: - break; - } + decimation--; + }; + const double acq_fs_decimated = static_cast(fs) / static_cast(decimation); - if (acq_fs < fs) + if (decimation > 1) { - // check if the resampler is already created for the channel system/signal and for the specific RF Channel - const std::string map_key = channels_.at(i)->get_signal().get_signal_str() + std::to_string(selected_signal_conditioner_ID); - resampler_ratio = static_cast(fs) / acq_fs; - int decimation = floor(resampler_ratio); - while (fs % decimation > 0) + // create a FIR low pass filter + std::vector taps = gr::filter::firdes::low_pass(1.0, + fs, + acq_fs_decimated / 2.1, + acq_fs_decimated / 2); + + gr::basic_block_sptr fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(decimation, taps); + + std::pair::iterator, bool> ret; + ret = acq_resamplers_.insert(std::pair(map_key, fir_filter_ccf_)); + if (ret.second == true) { - decimation--; - }; - const double acq_fs_decimated = static_cast(fs) / static_cast(decimation); - - if (decimation > 1) - { - // create a FIR low pass filter - std::vector taps = gr::filter::firdes::low_pass(1.0, - fs, - acq_fs_decimated / 2.1, - acq_fs_decimated / 2); - - gr::basic_block_sptr fir_filter_ccf_ = gr::filter::fir_filter_ccf::make(decimation, taps); - - std::pair::iterator, bool> ret; - ret = acq_resamplers_.insert(std::pair(map_key, fir_filter_ccf_)); - if (ret.second == true) - { - top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - acq_resamplers_.at(map_key), 0); - LOG(INFO) << "Created " - << channels_.at(i)->get_signal().get_signal_str() - << " acquisition resampler for RF channel " << std::to_string(signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; - } - else - { - LOG(INFO) << "Found existing " - << channels_.at(i)->get_signal().get_signal_str() - << " acquisition resampler for RF channel " << std::to_string(signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; - } - - top_block_->connect(acq_resamplers_.at(map_key), 0, - channels_.at(i)->get_left_block_acq(), 0); - - std::shared_ptr channel_ptr = std::dynamic_pointer_cast(channels_.at(i)); - channel_ptr->acquisition()->set_resampler_latency((taps.size() - 1) / 2); + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + acq_resamplers_.at(map_key), 0); + LOG(INFO) << "Created " + << channels_.at(i)->get_signal().get_signal_str() + << " acquisition resampler for RF channel " << std::to_string(selected_signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; } else { - LOG(INFO) << "Disabled acquisition resampler because the input sampling frequency is too low"; - // resampler not required! - top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - channels_.at(i)->get_left_block_acq(), 0); + LOG(INFO) << "Found existing " + << channels_.at(i)->get_signal().get_signal_str() + << " acquisition resampler for RF channel " << std::to_string(selected_signal_conditioner_ID) << " with " << taps.size() << " taps and decimation factor of " << decimation; } + + top_block_->connect(acq_resamplers_.at(map_key), 0, + channels_.at(i)->get_left_block_acq(), 0); + + std::shared_ptr channel_ptr = std::dynamic_pointer_cast(channels_.at(i)); + channel_ptr->acquisition()->set_resampler_latency((taps.size() - 1) / 2); } else { LOG(INFO) << "Disabled acquisition resampler because the input sampling frequency is too low"; + // resampler not required! top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, channels_.at(i)->get_left_block_acq(), 0); } } else { + LOG(INFO) << "Disabled acquisition resampler because the input sampling frequency is too low"; top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, channels_.at(i)->get_left_block_acq(), 0); } - top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - channels_.at(i)->get_left_block_trk(), 0); } - catch (const std::exception& e) + else { - LOG(WARNING) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_acq(), 0); } - signal_conditioner_connected.at(selected_signal_conditioner_ID) = true; // notify that this signal conditioner is connected - DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); } -#endif - // Signal Source > Signal conditioner >> Channels >> Observables + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i << ": " << e.what(); + top_block_->disconnect_all(); + return 1; + } + + signal_conditioner_connected_.at(selected_signal_conditioner_ID) = true; // annotate that this signal conditioner is connected + DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " successfully connected to channel " << i; + } + return 0; +} + + +int GNSSFlowgraph::disconnect_signal_conditioners_from_channels() +{ + for (int i = 0; i < channels_count_; i++) + { + int selected_signal_conditioner_ID; + try + { + selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << e.what(); + top_block_->disconnect_all(); + return 1; + } + try + { + top_block_->disconnect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block_trk(), 0); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i << ": " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + DLOG(INFO) << "Signal conditioner(s) sucessfully disconnected from channels"; + return 0; +} + + +int GNSSFlowgraph::connect_channels_to_observables() +{ + for (int i = 0; i < channels_count_; i++) + { try { top_block_->connect(channels_.at(i)->get_right_block(), 0, @@ -530,28 +1145,327 @@ void GNSSFlowgraph::connect() } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect channel " << i << " to observables"; - LOG(ERROR) << e.what(); + LOG(ERROR) << "Can't connect channel " << i << " to observables: " << e.what(); top_block_->disconnect_all(); - return; + return 1; + } + } + DLOG(INFO) << "Channel blocks successfully connected to the Observables block"; + return 0; +} + + +int GNSSFlowgraph::disconnect_channels_from_observables() +{ + for (int i = 0; i < channels_count_; i++) + { + try + { + top_block_->disconnect(channels_.at(i)->get_right_block(), 0, + observables_->get_left_block(), i); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect channel " << i << " to observables: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + +int GNSSFlowgraph::connect_observables_to_pvt() +{ + // Connect the observables output of each channel to the PVT block + try + { + for (int i = 0; i < channels_count_; i++) + { + top_block_->connect(observables_->get_right_block(), i, pvt_->get_left_block(), i); + top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); + } + + top_block_->msg_connect(observables_->get_right_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); + + top_block_->msg_connect(pvt_->get_left_block(), pmt::mp("pvt_to_observables"), observables_->get_right_block(), pmt::mp("pvt_to_observables")); + top_block_->msg_connect(pvt_->get_left_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect observables to PVT: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "Observables successfully connected to the PVT block"; + return 0; +} + + +int GNSSFlowgraph::disconnect_observables_from_pvt() +{ + try + { + for (int i = 0; i < channels_count_; i++) + { + top_block_->disconnect(observables_->get_right_block(), i, pvt_->get_left_block(), i); + top_block_->msg_disconnect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); + } + top_block_->msg_disconnect(observables_->get_right_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); + + top_block_->msg_disconnect(pvt_->get_left_block(), pmt::mp("pvt_to_observables"), observables_->get_right_block(), pmt::mp("pvt_to_observables")); + top_block_->msg_disconnect(pvt_->get_left_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect observables to PVT: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} + + +int GNSSFlowgraph::connect_gnss_synchro_monitor() +{ + try + { + for (int i = 0; i < channels_count_; i++) + { + top_block_->connect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); + } + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect observables to Monitor block: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "gnss_synchro_monitor successfully connected to Observables block"; + return 0; +} + + +int GNSSFlowgraph::connect_acquisition_monitor() +{ + try + { + for (int i = 0; i < channels_count_; i++) + { + top_block_->connect(channels_.at(i)->get_right_block_acq(), 0, GnssSynchroAcquisitionMonitor_, i); + } + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect acquisition intermediate outputs to Monitor block: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "acqusition_monitor successfully connected to Channel blocks"; + return 0; +} + + +int GNSSFlowgraph::connect_tracking_monitor() +{ + try + { + for (int i = 0; i < channels_count_; i++) + { + top_block_->connect(channels_.at(i)->get_right_block_trk(), 0, GnssSynchroTrackingMonitor_, i); + } + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect tracking outputs to Monitor block: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "tracking_monitor successfully connected to Channel blocks"; + return 0; +} + + +int GNSSFlowgraph::connect_monitors() +{ + // GNSS SYNCHRO MONITOR + if (enable_monitor_) + { + if (connect_gnss_synchro_monitor() != 0) + { + return 1; } } - // check for unconnected signal conditioners and connect null_sinks in order to provide configuration flexibility to multiband files or signal sources - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + // GNSS SYNCHRO ACQUISITION MONITOR + if (enable_acquisition_monitor_) { - for (size_t n = 0; n < sig_conditioner_.size(); n++) + if (connect_acquisition_monitor() != 0) { - if (signal_conditioner_connected.at(n) == false) + return 1; + } + } + + // GNSS SYNCHRO TRACKING MONITOR + if (enable_tracking_monitor_) + { + if (connect_tracking_monitor() != 0) + { + return 1; + } + } + + return 0; +} + + +int GNSSFlowgraph::disconnect_monitors() +{ + try + { + for (int i = 0; i < channels_count_; i++) + { + if (enable_monitor_) { - null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); - top_block_->connect(sig_conditioner_.at(n)->get_right_block(), 0, - null_sinks_.back(), 0); - LOG(INFO) << "Null sink connected to signal conditioner " << n << " due to lack of connection to any channel\n"; + top_block_->disconnect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); + } + if (enable_acquisition_monitor_) + { + top_block_->disconnect(channels_.at(i)->get_right_block_acq(), 0, GnssSynchroAcquisitionMonitor_, i); + } + if (enable_tracking_monitor_) + { + top_block_->disconnect(channels_.at(i)->get_right_block_trk(), 0, GnssSynchroTrackingMonitor_, i); } } } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect monitors: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + return 0; +} + +int GNSSFlowgraph::connect_signal_conditioners() +{ + for (auto& sig : sig_conditioner_) + { + try + { + sig->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect signal conditioner block internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + DLOG(INFO) << "Signal Conditioner blocks successfully connected to the top_block"; + return 0; +} + + +int GNSSFlowgraph::disconnect_signal_conditioners() +{ + for (auto& sig : sig_conditioner_) + { + try + { + sig->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal conditioner block internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + +int GNSSFlowgraph::disconnect_signal_sources_from_signal_conditioners() +{ + int RF_Channels = 0; + int signal_conditioner_ID = 0; + for (int i = 0; i < sources_count_; i++) + { + try + { + // TODO: Remove this array implementation and create generic multistream connector + // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") + { + // Multichannel Array + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); + } + } + else + { + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) + { + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + } + signal_conditioner_ID++; + } + } + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + +void GNSSFlowgraph::check_signal_conditioners() +{ + // check for unconnected signal conditioners and connect null_sinks + // in order to provide configuration flexibility to multiband files or signal sources + for (size_t n = 0; n < sig_conditioner_.size(); n++) + { + if (signal_conditioner_connected_.at(n) == false) + { + null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); + top_block_->connect(sig_conditioner_.at(n)->get_right_block(), 0, + null_sinks_.back(), 0); + LOG(INFO) << "Null sink connected to signal conditioner " << n << " due to lack of connection to any channel\n"; + } + } +} + + +void GNSSFlowgraph::assign_channels() +{ // Put channels fixed to a given satellite at the beginning of the vector, then the rest std::vector vector_of_channels; for (int i = 0; i < channels_count_; i++) @@ -680,427 +1594,6 @@ void GNSSFlowgraph::connect() channels_.at(i)->set_signal(signal_value); } } - - // Connect the observables output of each channel to the PVT block - try - { - for (int i = 0; i < channels_count_; i++) - { - top_block_->connect(observables_->get_right_block(), i, pvt_->get_left_block(), i); - top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); - } - - top_block_->msg_connect(observables_->get_right_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); - - top_block_->msg_connect(pvt_->get_left_block(), pmt::mp("pvt_to_observables"), observables_->get_right_block(), pmt::mp("pvt_to_observables")); - top_block_->msg_connect(pvt_->get_left_block(), pmt::mp("status"), channels_status_, pmt::mp("status")); - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect observables to PVT"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - - // GNSS SYNCHRO MONITOR - if (enable_monitor_) - { - try - { - for (int i = 0; i < channels_count_; i++) - { - top_block_->connect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); - } - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect observables to Monitor block"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } - - // GNSS SYNCHRO ACQUISITION MONITOR - if (enable_acquisition_monitor_) - { - try - { - for (int i = 0; i < channels_count_; i++) - { - top_block_->connect(channels_.at(i)->get_right_block_acq(), 0, GnssSynchroAcquisitionMonitor_, i); - } - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect acquisition intermediate outputs to Monitor block"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } - - // GNSS SYNCHRO TRACKING MONITOR - if (enable_tracking_monitor_) - { - try - { - for (int i = 0; i < channels_count_; i++) - { - top_block_->connect(channels_.at(i)->get_right_block_trk(), 0, GnssSynchroTrackingMonitor_, i); - } - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect tracking outputs to Monitor block"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } -#ifndef ENABLE_FPGA - // Activate acquisition in enabled channels - for (int i = 0; i < channels_count_; i++) - { - LOG(INFO) << "Channel " << i << " assigned to " << channels_.at(i)->get_signal(); - if (channels_state_[i] == 1) - { - channels_.at(i)->start_acquisition(); - LOG(INFO) << "Channel " << i << " connected to observables and ready for acquisition"; - } - else - { - LOG(INFO) << "Channel " << i << " connected to observables in standby mode"; - } - } -#endif - connected_ = true; - LOG(INFO) << "Flowgraph connected"; - top_block_->dump(); -} - - -void GNSSFlowgraph::disconnect() -{ - LOG(INFO) << "Disconnecting flowgraph"; - - if (!connected_) - { - LOG(INFO) << "flowgraph was not connected"; - return; - } - connected_ = false; - // Signal Source (i) > Signal conditioner (i) > - int RF_Channels = 0; - int signal_conditioner_ID = 0; -#ifdef ENABLE_FPGA - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) - { - for (int i = 0; i < sources_count_; i++) - { - try - { - // TODO: Remove this array implementation and create generic multistream connector - // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") - { - // Multichannel Array - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } - } - else - { - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - - for (int j = 0; j < RF_Channels; j++) - { - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - if (j == 0) - { - // RF_channel 0 backward compatibility with single channel sources - top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - } - signal_conditioner_ID++; - } - } - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); - top_block_->disconnect_all(); - return; - } - } - } -#else - for (int i = 0; i < sources_count_; i++) - { - try - { - // TODO: Remove this array implementation and create generic multistream connector - // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") - { - // Multichannel Array - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } - } - else - { - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - - for (int j = 0; j < RF_Channels; j++) - { - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - if (j == 0) - { - // RF_channel 0 backward compatibility with single channel sources - top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - } - signal_conditioner_ID++; - } - } - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); - top_block_->disconnect_all(); - return; - } - } -#endif - -#ifdef ENABLE_FPGA - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) - { - // disconnect the signal source to sample counter - // disconnect the sample counter to Observables - try - { - top_block_->disconnect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); - top_block_->disconnect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't disconnect sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } - else - { - try - { - top_block_->disconnect(ch_out_fpga_sample_counter_, 0, observables_->get_left_block(), channels_count_); - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect FPGA sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - } -#else - // disconnect the signal source to sample counter - // disconnect the sample counter to Observables - try - { - top_block_->disconnect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter_, 0); - top_block_->disconnect(ch_out_sample_counter_, 0, observables_->get_left_block(), channels_count_); // extra port for the sample counter pulse - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect sample counter"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } -#endif - // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) - for (int i = 0; i < channels_count_; i++) - { -#ifndef ENABLE_FPGA - int selected_signal_conditioner_ID; - try - { - selected_signal_conditioner_ID = configuration_->property("Channel" + std::to_string(i) + ".RF_channel_ID", 0); - } - catch (const std::exception& e) - { - LOG(WARNING) << e.what(); - top_block_->disconnect_all(); - return; - } - try - { - top_block_->disconnect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - channels_.at(i)->get_left_block_trk(), 0); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i << ": " << e.what(); - top_block_->disconnect_all(); - return; - } -#endif - // Signal Source > Signal conditioner >> Channels >> Observables - try - { - top_block_->disconnect(channels_.at(i)->get_right_block(), 0, - observables_->get_left_block(), i); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect channel " << i << " to observables: " << e.what(); - top_block_->disconnect_all(); - return; - } - } - - try - { - for (int i = 0; i < channels_count_; i++) - { - top_block_->disconnect(observables_->get_right_block(), i, pvt_->get_left_block(), i); - if (enable_monitor_) - { - top_block_->disconnect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); - } - if (enable_acquisition_monitor_) - { - top_block_->disconnect(channels_.at(i)->get_right_block_acq(), 0, GnssSynchroAcquisitionMonitor_, i); - } - if (enable_tracking_monitor_) - { - top_block_->disconnect(channels_.at(i)->get_right_block_trk(), 0, GnssSynchroTrackingMonitor_, i); - } - top_block_->msg_disconnect(channels_.at(i)->get_right_block(), pmt::mp("telemetry"), pvt_->get_left_block(), pmt::mp("telemetry")); - } - top_block_->msg_disconnect(pvt_->get_left_block(), pmt::mp("pvt_to_observables"), observables_->get_right_block(), pmt::mp("pvt_to_observables")); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect observables to PVT: " << e.what(); - top_block_->disconnect_all(); - return; - } - - for (int i = 0; i < sources_count_; i++) - { - try - { - sig_source_.at(i)->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal source block " << i << " internally: " << e.what(); - top_block_->disconnect_all(); - return; - } - } - - // Signal Source > Signal conditioner > - for (auto& sig : sig_conditioner_) - { - try - { - sig->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal conditioner block internally: " << e.what(); - top_block_->disconnect_all(); - return; - } - } - - for (int i = 0; i < channels_count_; i++) - { - try - { - channels_.at(i)->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect channel " << i << " internally: " << e.what(); - top_block_->disconnect_all(); - return; - } - } - - try - { - observables_->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect observables block internally: " << e.what(); - top_block_->disconnect_all(); - return; - } - - // Signal Source > Signal conditioner >> Channels >> Observables > PVT - try - { - pvt_->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect PVT block internally: " << e.what(); - top_block_->disconnect_all(); - return; - } - - DLOG(INFO) << "blocks disconnected internally"; - LOG(INFO) << "Flowgraph disconnected"; -} - - -void GNSSFlowgraph::wait() -{ - if (!running_) - { - LOG(WARNING) << "Can't apply wait. Flowgraph is not running"; - return; - } - top_block_->wait(); - DLOG(INFO) << "Flowgraph finished calculations"; - running_ = false; } @@ -1315,12 +1808,12 @@ void GNSSFlowgraph::acquisition_manager(unsigned int who) // set Doppler center to 0 Hz channels_[current_channel]->assist_acquisition_doppler(0); } -#ifndef ENABLE_FPGA - channels_[current_channel]->start_acquisition(); -#else +#if ENABLE_FPGA // create a task for the FPGA such that it doesn't stop the flow std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[current_channel]); tmp_thread.detach(); +#else + channels_[current_channel]->start_acquisition(); #endif } else @@ -1420,12 +1913,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) acq_channels_count_++; DLOG(INFO) << "Channel " << who << " Starting acquisition " << gs.get_satellite() << ", Signal " << gs.get_signal_str(); channels_[who]->set_signal(channels_[who]->get_signal()); -#ifndef ENABLE_FPGA - channels_[who]->start_acquisition(); -#else + +#if ENABLE_FPGA // create a task for the FPGA such that it doesn't stop the flow std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[who]); tmp_thread.detach(); +#else + channels_[who]->start_acquisition(); #endif } else @@ -1544,7 +2038,7 @@ void GNSSFlowgraph::set_configuration(const std::shared_ptr(); - - channels_status_ = channel_status_msg_receiver_make(); - - // 1. read the number of RF front-ends available (one file_source per RF front-end) - sources_count_ = configuration_->property("Receiver.sources_count", 1); - - int RF_Channels = 0; - int signal_conditioner_ID = 0; - - if (sources_count_ > 1) - { - for (int i = 0; i < sources_count_; i++) - { - std::cout << "Creating source " << i << '\n'; - sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), i)); - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - std::cout << "RF Channels " << RF_Channels << '\n'; - for (int j = 0; j < RF_Channels; j++) - { - sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); - signal_conditioner_ID++; - } - } - } - else - { - // backwards compatibility for old config files - sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), -1)); - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); - if (RF_Channels != 0) - { - for (int j = 0; j < RF_Channels; j++) - { - sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), signal_conditioner_ID)); - signal_conditioner_ID++; - } - } - else - { - // old config file, single signal source and single channel, not specified - sig_conditioner_.push_back(block_factory->GetSignalConditioner(configuration_.get(), -1)); - } - } - - observables_ = block_factory->GetObservables(configuration_.get()); - - pvt_ = block_factory->GetPVT(configuration_.get()); - - auto channels = block_factory->GetChannels(configuration_.get(), queue_.get()); - - channels_count_ = static_cast(channels->size()); - for (int i = 0; i < channels_count_; i++) - { - std::shared_ptr chan_ = std::move(channels->at(i)); - channels_.push_back(std::dynamic_pointer_cast(chan_)); - } - - top_block_ = gr::make_top_block("GNSSFlowgraph"); - - mapStringValues_["1C"] = evGPS_1C; - mapStringValues_["2S"] = evGPS_2S; - mapStringValues_["L5"] = evGPS_L5; - mapStringValues_["1B"] = evGAL_1B; - mapStringValues_["5X"] = evGAL_5X; - mapStringValues_["7X"] = evGAL_7X; - mapStringValues_["E6"] = evGAL_E6; - mapStringValues_["1G"] = evGLO_1G; - mapStringValues_["2G"] = evGLO_2G; - mapStringValues_["B1"] = evBDS_B1; - mapStringValues_["B3"] = evBDS_B3; - - // fill the signals queue with the satellites ID's to be searched by the acquisition - set_signals_list(); - set_channels_state(); - DLOG(INFO) << "Blocks instantiated. " << channels_count_ << " channels."; - - /* - * Instantiate the receiver monitor block, if required - */ - enable_monitor_ = configuration_->property("Monitor.enable_monitor", false); - if (enable_monitor_) - { - // Retrieve monitor properties - bool enable_protobuf = configuration_->property("Monitor.enable_protobuf", true); - if (configuration_->property("PVT.enable_protobuf", false) == true) - { - enable_protobuf = true; - } - std::string address_string = configuration_->property("Monitor.client_addresses", std::string("127.0.0.1")); - std::vector udp_addr_vec = split_string(address_string, '_'); - std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); - udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); - - // Instantiate monitor object - GnssSynchroMonitor_ = gnss_synchro_make_monitor(channels_count_, - configuration_->property("Monitor.decimation_factor", 1), - configuration_->property("Monitor.udp_port", 1234), - udp_addr_vec, enable_protobuf); - } - - /* - * Instantiate the receiver acquisition monitor block, if required - */ - enable_acquisition_monitor_ = configuration_->property("AcquisitionMonitor.enable_monitor", false); - if (enable_acquisition_monitor_) - { - // Retrieve monitor properties - bool enable_protobuf = configuration_->property("AcquisitionMonitor.enable_protobuf", true); - if (configuration_->property("PVT.enable_protobuf", false) == true) - { - enable_protobuf = true; - } - std::string address_string = configuration_->property("AcquisitionMonitor.client_addresses", std::string("127.0.0.1")); - std::vector udp_addr_vec = split_string(address_string, '_'); - std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); - udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); - - GnssSynchroAcquisitionMonitor_ = gnss_synchro_make_monitor(channels_count_, - configuration_->property("AcquisitionMonitor.decimation_factor", 1), - configuration_->property("AcquisitionMonitor.udp_port", 1235), - udp_addr_vec, enable_protobuf); - } - - /* - * Instantiate the receiver tracking monitor block, if required - */ - enable_tracking_monitor_ = configuration_->property("TrackingMonitor.enable_monitor", false); - if (enable_tracking_monitor_) - { - // Retrieve monitor properties - bool enable_protobuf = configuration_->property("TrackingMonitor.enable_protobuf", true); - if (configuration_->property("PVT.enable_protobuf", false) == true) - { - enable_protobuf = true; - } - std::string address_string = configuration_->property("TrackingMonitor.client_addresses", std::string("127.0.0.1")); - std::vector udp_addr_vec = split_string(address_string, '_'); - std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); - udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); - - GnssSynchroTrackingMonitor_ = gnss_synchro_make_monitor(channels_count_, - configuration_->property("TrackingMonitor.decimation_factor", 1), - configuration_->property("TrackingMonitor.udp_port", 1236), - udp_addr_vec, enable_protobuf); - } -} - - std::vector GNSSFlowgraph::split_string(const std::string& s, char delim) { std::vector v; diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index a7ba709e4..49a004589 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -153,7 +153,7 @@ public: */ void priorize_satellites(const std::vector>& visible_satellites); -#ifdef ENABLE_FPGA +#if ENABLE_FPGA void start_acquisition_helper(); void perform_hw_reset(); @@ -161,6 +161,49 @@ public: private: void init(); // Populates the SV PRN list available for acquisition and tracking + int connect_desktop_flowgraph(); + + int connect_signal_sources(); + int connect_signal_conditioners(); + int connect_channels(); + int connect_observables(); + int connect_pvt(); + int connect_sample_counter(); + + int connect_signal_sources_to_signal_conditioners(); + int connect_signal_conditioners_to_channels(); + int connect_channels_to_observables(); + int connect_observables_to_pvt(); + int connect_monitors(); + int connect_gnss_synchro_monitor(); + int connect_acquisition_monitor(); + int connect_tracking_monitor(); + + int disconnect_desktop_flowgraph(); + + int disconnect_signal_sources(); + int disconnect_signal_conditioners(); + int disconnect_channels(); + int disconnect_observables(); + int disconnect_pvt(); + int disconnect_sample_counter(); + + int disconnect_signal_sources_from_signal_conditioners(); + int disconnect_signal_conditioners_from_channels(); + int disconnect_channels_from_observables(); + int disconnect_observables_from_pvt(); + int disconnect_monitors(); + +#if ENABLE_FPGA + int connect_fpga_flowgraph(); + int disconnect_fpga_flowgraph(); + int connect_fpga_sample_counter(); + int disconnect_fpga_sample_counter(); +#endif + + void assign_channels(); + void check_signal_conditioners(); + void set_signals_list(); void set_channels_state(); // Initializes the channels state (start acquisition or keep standby) // using the configuration parameters (number of channels and max channels in acquisition) @@ -178,6 +221,7 @@ private: bool is_multiband() const; std::vector split_string(const std::string& s, char delim); + std::vector signal_conditioner_connected_; gr::top_block_sptr top_block_; From a21c60ecb221337de6844b01e3ea94b46361bde6 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 24 Jan 2021 01:49:16 +0100 Subject: [PATCH 02/12] Improve error handling when the flow graph fails to start Avoid segmentation faults due to some common inconsistencies in the configuration file E.g.: non-existing names for blocks implementation, some mismatched input/output item sizes Provide hints to the user on how to fix the configuration in case of failure when starting the flow graph --- docs/changelog.md | 9 + .../adapters/signal_conditioner.cc | 13 + src/core/receiver/control_thread.cc | 2 - src/core/receiver/gnss_block_factory.cc | 18 +- src/core/receiver/gnss_flowgraph.cc | 365 ++++++++++++------ src/core/receiver/gnss_flowgraph.h | 3 + 6 files changed, 283 insertions(+), 127 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index aed239a7b..8300fc858 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -28,6 +28,15 @@ SPDX-FileCopyrightText: 2011-2021 Carles Fernandez-Prades +#include #include @@ -40,6 +41,18 @@ void SignalConditioner::connect(gr::top_block_sptr top_block) LOG(WARNING) << "Signal conditioner already connected internally"; return; } + if (data_type_adapt_ == nullptr) + { + throw std::invalid_argument("DataTypeAdapter implementation not defined"); + } + if (in_filt_ == nullptr) + { + throw std::invalid_argument("InputFilter implementation not defined"); + } + if (res_ == nullptr) + { + throw std::invalid_argument("Resampler implementation not defined"); + } data_type_adapt_->connect(top_block); in_filt_->connect(top_block); res_->connect(top_block); diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index e0642f15c..5ab055c9a 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -300,7 +300,6 @@ int ControlThread::run() } else { - LOG(ERROR) << "Unable to connect flowgraph"; return 0; } // Start the flowgraph @@ -311,7 +310,6 @@ int ControlThread::run() } else { - LOG(ERROR) << "Unable to start flowgraph"; return 0; } diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 8e30d9caf..67ab07687 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -374,6 +374,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel( if (acq_item_type != trk_item_type) { LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; + return nullptr; } LOG(INFO) << "Instantiating Channel " << channel @@ -388,6 +389,11 @@ std::unique_ptr GNSSBlockFactory::GetChannel( std::unique_ptr trk_ = GetTrkBlock(configuration, "Tracking_" + signal + appendix2, 1, 1); std::unique_ptr tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_" + signal + appendix3, 1, 1); + if (acq_ == nullptr or trk_ == nullptr or tlm_ == nullptr) + { + return nullptr; + } + std::unique_ptr channel_ = std::make_unique(configuration, channel, std::move(acq_), std::move(trk_), @@ -1320,8 +1326,7 @@ std::unique_ptr GNSSBlockFactory::GetBlock( else { - // Log fatal. This causes execution to stop. - LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; + LOG(ERROR) << role << " block: Undefined implementation " << implementation; } return block; } @@ -1515,8 +1520,7 @@ std::unique_ptr GNSSBlockFactory::GetAcqBlock( else { - // Log fatal. This causes execution to stop. - LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; + LOG(ERROR) << role << " block: Undefined implementation " << implementation; } return block; } @@ -1671,8 +1675,7 @@ std::unique_ptr GNSSBlockFactory::GetTrkBlock( #endif else { - // Log fatal. This causes execution to stop. - LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; + LOG(ERROR) << role << " block: Undefined implementation " << implementation; } return block; } @@ -1764,8 +1767,7 @@ std::unique_ptr GNSSBlockFactory::GetTlmBlock( else { - // Log fatal. This causes execution to stop. - LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; + LOG(ERROR) << role << " block: Undefined implementation " << implementation; } return block; } diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 1566f3616..d37970fbd 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -128,7 +128,10 @@ void GNSSFlowgraph::init() // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. // Include GetRFChannels in the interface to avoid read config parameters here // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); + if (sig_source_.at(0) != nullptr) + { + RF_Channels = configuration_->property(sig_source_.at(0)->role() + ".RF_channels", 0); + } if (RF_Channels != 0) { for (int j = 0; j < RF_Channels; j++) @@ -265,6 +268,7 @@ void GNSSFlowgraph::start() catch (const std::exception& e) { LOG(ERROR) << "Unable to start flowgraph: " << e.what(); + print_help(); return; } @@ -321,11 +325,15 @@ void GNSSFlowgraph::connect() #if ENABLE_FPGA if (connect_fpga_flowgraph() != 0) { + LOG(ERROR) << "Unable to connect flowgraph with FPFA off-loading"; + print_help(); return; } #else if (connect_desktop_flowgraph() != 0) { + LOG(ERROR) << "Unable to connect flowgraph"; + print_help(); return; } #endif @@ -342,7 +350,7 @@ void GNSSFlowgraph::disconnect() if (!connected_) { - LOG(INFO) << "flowgraph was not connected"; + LOG(INFO) << "Flowgraph was not connected"; return; } connected_ = false; @@ -539,19 +547,28 @@ int GNSSFlowgraph::connect_fpga_flowgraph() DLOG(INFO) << "Blocks connected internally to the top_block"; // Connect the counter - if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + if (sig_source_.at(0) != nullptr) { - if (connect_sample_counter() != 0) + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) { - return 1; + if (connect_sample_counter() != 0) + { + return 1; + } + } + else + { + if (connect_fpga_sample_counter() != 0) + { + return 1; + } } } else { - if (connect_fpga_sample_counter() != 0) - { - return 1; - } + help_hint_ += " * Check implementation name for SignalSource block\n"; + help_hint_ += " Signal Source block implementation for FPGA off-loading should be 'Ad9361_Fpga_Signal_Source'\n"; + return 1; } if (connect_channels_to_observables() != 0) @@ -575,6 +592,9 @@ int GNSSFlowgraph::connect_fpga_flowgraph() { return 1; } + + check_desktop_conf_in_fpga_env(); + LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration with FPGA off-loading has been successfully connected"; return 0; } @@ -654,13 +674,23 @@ int GNSSFlowgraph::connect_signal_sources() { for (int i = 0; i < sources_count_; i++) { - try + if (sig_source_.at(i) != nullptr) { - sig_source_.at(i)->connect(top_block_); + try + { + sig_source_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect signal source block " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } } - catch (const std::exception& e) + else { - LOG(ERROR) << "Can't connect signal source block " << i << " internally: " << e.what(); + help_hint_ += " * Check implementation name for SignalSource" + (i == 0 ? " " : (std::to_string(i) + " ")) + "block\n"; + help_hint_ += " Signal Source blocks documentation at https://gnss-sdr.org/docs/sp-blocks/signal-source/\n"; top_block_->disconnect_all(); return 1; } @@ -689,17 +719,95 @@ int GNSSFlowgraph::disconnect_signal_sources() } +int GNSSFlowgraph::connect_signal_conditioners() +{ + for (auto& sig : sig_conditioner_) + { + try + { + sig->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect signal conditioner block internally: " << e.what(); + top_block_->disconnect_all(); + std::string reported_error(e.what()); + if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) + { + std::string replace_me("copy"); + size_t pos = reported_error.find(replace_me); + size_t len = replace_me.length(); + reported_error.replace(pos, len, "PassThrough"); + help_hint_ += " * Blocks within the Signal Conditioner are connected with mismatched item size\n"; + help_hint_ += " Reported error: " + reported_error + '\n'; + help_hint_ += " Check the Signal Conditioner documentation at https://gnss-sdr.org/docs/sp-blocks/signal-conditioner/\n"; + } + if (std::string::npos != reported_error.find(std::string("DataTypeAdapter"))) + { + help_hint_ += " * The DataTypeAdapter implementation set in the configuration file does not exist\n"; + help_hint_ += " Check the DataTypeAdapter documentation at https://gnss-sdr.org/docs/sp-blocks/data-type-adapter/\n"; + } + if (std::string::npos != reported_error.find(std::string("InputFilter"))) + { + help_hint_ += " * The InputFilter implementation set in the configuration file does not exist\n"; + help_hint_ += " Check the InputFilter documentation at https://gnss-sdr.org/docs/sp-blocks/input-filter/\n"; + } + if (std::string::npos != reported_error.find(std::string("Resampler"))) + { + help_hint_ += " * The Resampler implementation set in the configuration file does not exist\n"; + help_hint_ += " Check the Resampler documentation at https://gnss-sdr.org/docs/sp-blocks/resampler/\n"; + } + return 1; + } + } + DLOG(INFO) << "Signal Conditioner blocks successfully connected to the top_block"; + return 0; +} + + +int GNSSFlowgraph::disconnect_signal_conditioners() +{ + for (auto& sig : sig_conditioner_) + { + try + { + sig->disconnect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal conditioner block internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + int GNSSFlowgraph::connect_channels() { for (int i = 0; i < channels_count_; i++) { - try + if (channels_.at(i) != nullptr) { - channels_.at(i)->connect(top_block_); + try + { + channels_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect channel " << i << " internally: " << e.what(); + top_block_->disconnect_all(); + return 1; + } } - catch (const std::exception& e) + else { - LOG(ERROR) << "Can't connect channel " << i << " internally: " << e.what(); + LOG(ERROR) << "Can't connect channel " << i << " internally"; + help_hint_ += " * Check implementation names for Channel" + std::to_string(i) + " inner blocks.\n"; + help_hint_ += " Acquisition blocks documentation at https://gnss-sdr.org/docs/sp-blocks/acquisition/\n"; + help_hint_ += " Tracking blocks documentation at https://gnss-sdr.org/docs/sp-blocks/tracking/\n"; + help_hint_ += " Telemetry Decoder blocks documentation at https://gnss-sdr.org/docs/sp-blocks/telemetry-decoder/\n"; top_block_->disconnect_all(); return 1; } @@ -730,6 +838,13 @@ int GNSSFlowgraph::disconnect_channels() int GNSSFlowgraph::connect_observables() { + if (observables_ == nullptr) + { + help_hint_ += " * Check implementation name for the Observables block\n"; + help_hint_ += " Observables block documentation at https://gnss-sdr.org/docs/sp-blocks/observables/\n"; + top_block_->disconnect_all(); + return 1; + } try { observables_->connect(top_block_); @@ -763,6 +878,13 @@ int GNSSFlowgraph::disconnect_observables() int GNSSFlowgraph::connect_pvt() { + if (pvt_ == nullptr) + { + help_hint_ += " * Check implementation name for the PVT block\n"; + help_hint_ += " PVT block documentation at https://gnss-sdr.org/docs/sp-blocks/pvt/\n"; + top_block_->disconnect_all(); + return 1; + } try { pvt_->connect(top_block_); @@ -840,6 +962,7 @@ int GNSSFlowgraph::disconnect_sample_counter() return 0; } + #if ENABLE_FPGA int GNSSFlowgraph::connect_fpga_sample_counter() { @@ -918,6 +1041,8 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() // GNURADIO max_streams=-1 means infinite ports! DLOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); DLOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); + size_t output_size = sig_source_.at(i)->item_size(); + size_t input_size = sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->sizeof_stream_item(0); if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) { @@ -943,12 +1068,28 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() } } signal_conditioner_ID++; + // Check configuration inconsistencies + if (output_size != input_size) + { + help_hint_ += " * The Signal Source implementation " + sig_source_.at(i)->implementation() + " has an output with an item size of " + std::to_string(output_size) + " bytes, but it is connected to the Signal Conditioner implementation " + sig_conditioner_.at(signal_conditioner_ID)->implementation() + " with input item size of " + std::to_string(input_size) + "bytes.\n"; + help_hint_ += " Output ports must be connected to input ports with the same item size.\n"; + } } } } catch (const std::exception& e) { - LOG(ERROR) << "Can't connect signal source " << i << " to signal conditioner " << i << ": " << e.what(); + LOG(ERROR) << "Can't connect SignalSource" << (i == 0 ? " " : (std::to_string(i) + " ")) << "to SignalConditioner" << (i == 0 ? " " : (std::to_string(i) + " ")) << ": " << e.what(); + std::string reported_error(e.what()); + if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) + { + std::string replace_me("copy"); + size_t pos = reported_error.find(replace_me); + size_t len = replace_me.length(); + reported_error.replace(pos, len, "PassThrough"); + help_hint_ += " * The SignalSource output item size and the SignalConditioner input item size are mismatched\n"; + help_hint_ += " Reported error: " + reported_error + '\n'; + } top_block_->disconnect_all(); return 1; } @@ -959,6 +1100,65 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() } +int GNSSFlowgraph::disconnect_signal_sources_from_signal_conditioners() +{ + int RF_Channels = 0; + int signal_conditioner_ID = 0; + for (int i = 0; i < sources_count_; i++) + { + try + { + // TODO: Remove this array implementation and create generic multistream connector + // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") + { + // Multichannel Array + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); + } + } + else + { + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) + { + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + } + signal_conditioner_ID++; + } + } + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); + top_block_->disconnect_all(); + return 1; + } + } + return 0; +} + + int GNSSFlowgraph::connect_signal_conditioners_to_channels() { for (int i = 0; i < channels_count_; i++) @@ -1096,7 +1296,7 @@ int GNSSFlowgraph::connect_signal_conditioners_to_channels() } signal_conditioner_connected_.at(selected_signal_conditioner_ID) = true; // annotate that this signal conditioner is connected - DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " successfully connected to channel " << i; + DLOG(INFO) << "Signal conditioner " << selected_signal_conditioner_ID << " successfully connected to channel " << i; } return 0; } @@ -1349,104 +1549,6 @@ int GNSSFlowgraph::disconnect_monitors() } -int GNSSFlowgraph::connect_signal_conditioners() -{ - for (auto& sig : sig_conditioner_) - { - try - { - sig->connect(top_block_); - } - catch (const std::exception& e) - { - LOG(ERROR) << "Can't connect signal conditioner block internally: " << e.what(); - top_block_->disconnect_all(); - return 1; - } - } - DLOG(INFO) << "Signal Conditioner blocks successfully connected to the top_block"; - return 0; -} - - -int GNSSFlowgraph::disconnect_signal_conditioners() -{ - for (auto& sig : sig_conditioner_) - { - try - { - sig->disconnect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal conditioner block internally: " << e.what(); - top_block_->disconnect_all(); - return 1; - } - } - return 0; -} - - -int GNSSFlowgraph::disconnect_signal_sources_from_signal_conditioners() -{ - int RF_Channels = 0; - int signal_conditioner_ID = 0; - for (int i = 0; i < sources_count_; i++) - { - try - { - // TODO: Remove this array implementation and create generic multistream connector - // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") - { - // Multichannel Array - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } - } - else - { - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - - for (int j = 0; j < RF_Channels; j++) - { - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) - { - top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - if (j == 0) - { - // RF_channel 0 backward compatibility with single channel sources - top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - } - signal_conditioner_ID++; - } - } - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); - top_block_->disconnect_all(); - return 1; - } - } - return 0; -} - - void GNSSFlowgraph::check_signal_conditioners() { // check for unconnected signal conditioners and connect null_sinks @@ -1597,6 +1699,35 @@ void GNSSFlowgraph::assign_channels() } +void GNSSFlowgraph::print_help() +{ + if (!help_hint_.empty()) + { + std::cerr << "It seems that your configuration file is not well defined.\n"; + std::cerr << "A hint to fix your configuration file:\n"; + std::cerr << help_hint_; + } +} + + +void GNSSFlowgraph::check_desktop_conf_in_fpga_env() +{ + int number_of_fpga_acq_channels = 0; + for (int i = 0; i < channels_count_; i++) + { + if (channels_.at(i)->get_left_block_acq() == nullptr) + { + number_of_fpga_acq_channels++; + } + } + if (number_of_fpga_acq_channels != channels_count_) + { + help_hint_ += " * The Acquisition block implementation is not suitable for GNSS-SDR flowgraph with FPGA off-loading\n"; + help_hint_ += " If you want to use this configuration in an environment without FPGA, please rebuild GNSS-SDR with CMake option '-DENABLE_FPGA=OFF'\n"; + } +} + + bool GNSSFlowgraph::send_telemetry_msg(const pmt::pmt_t& msg) { // Push ephemeris to PVT telemetry msg in port using a channel out port diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index 49a004589..8b71bb672 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -216,6 +216,8 @@ private: void push_back_signal(const Gnss_Signal& gs); void remove_signal(const Gnss_Signal& gs); + void print_help(); + void check_desktop_conf_in_fpga_env(); double project_doppler(const std::string& searched_signal, double primary_freq_doppler_hz); bool is_multiband() const; @@ -279,6 +281,7 @@ private: std::map mapStringValues_; std::string config_file_; + std::string help_hint_; std::mutex signal_list_mutex_; From cd1c9e46ba09ad68600bfd1fdf4714e47b314a6e Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 25 Jan 2021 00:49:36 +0100 Subject: [PATCH 03/12] Add some basic configuration checks Avoid some segmentation faults caused by ill-formatted configuration files --- src/core/libs/INIReader.cc | 20 ++++++ src/core/libs/INIReader.h | 6 ++ src/core/receiver/control_thread.cc | 96 +++++++++++++++++++++++-- src/core/receiver/control_thread.h | 7 ++ src/core/receiver/file_configuration.cc | 6 ++ src/core/receiver/file_configuration.h | 1 + 6 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/core/libs/INIReader.cc b/src/core/libs/INIReader.cc index f45ddcc9e..440a1fd75 100644 --- a/src/core/libs/INIReader.cc +++ b/src/core/libs/INIReader.cc @@ -81,3 +81,23 @@ int INIReader::ValueHandler(void* user, const char* section, const char* name, reader->_values[MakeKey(section, name)] = value; return 1; } + + +bool INIReader::HasSection(const std::string& section) const +{ + const std::string key = MakeKey(section, ""); + auto pos = _values.lower_bound(key); + if (pos == _values.end()) + { + return false; + } + // Does the key at the lower_bound pos start with "section"? + return pos->first.compare(0, key.length(), key) == 0; +} + + +bool INIReader::HasValue(const std::string& section, const std::string& name) const +{ + std::string key = MakeKey(section, name); + return _values.count(key); +} diff --git a/src/core/libs/INIReader.h b/src/core/libs/INIReader.h index 0cd269a38..1e2c751b7 100644 --- a/src/core/libs/INIReader.h +++ b/src/core/libs/INIReader.h @@ -58,6 +58,12 @@ public: //! Get an integer (long) value from INI file, returning default_value if not found. int64_t GetInteger(const std::string& section, const std::string& name, int64_t default_value); + //! Return true if the given section exists (section must contain at least one name=value pair). + bool HasSection(const std::string& section) const; + + //! Return true if a value exists with the given section and field names. + bool HasValue(const std::string& section, const std::string& name) const; + private: static std::string MakeKey(const std::string& section, const std::string& name); static int ValueHandler(void* user, const char* section, const char* name, diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index 5ab055c9a..302cd3a4f 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -83,6 +83,41 @@ ControlThread::ControlThread() { configuration_ = std::make_shared(FLAGS_c); } + // Basic configuration checks + auto aux = std::dynamic_pointer_cast(configuration_); + conf_file_has_section_ = aux->has_section(); + + conf_file_has_mandatory_globals_ = (configuration_->property("GNSS-SDR.internal_fs_sps", 0) == 0 ? false : true); + + const std::string empty_implementation; + std::string src_impl = configuration_->property("SignalSource.implementation", empty_implementation); + int src_count = configuration_->property("Receiver.sources_count", 1); + if (src_impl.empty() && (src_count != 1)) + { + int num_src = 0; + for (int i = 0; i < src_count; i++) + { + std::string src_impl_multiple = configuration_->property("SignalSource" + std::to_string(i) + ".implementation", empty_implementation); + if (!src_impl_multiple.empty()) + { + num_src++; + } + } + if (num_src != src_count) + { + src_impl = std::string(""); + } + } + conf_has_signal_sources_ = !src_impl.empty(); + + std::string pvt_impl = configuration_->property("PVT.implementation", empty_implementation); + conf_has_pvt_ = !pvt_impl.empty(); + + std::string obs_impl = configuration_->property("Observables.implementation", empty_implementation); + conf_has_observables_ = !obs_impl.empty(); + + well_formatted_configuration_ = conf_file_has_section_ && conf_file_has_mandatory_globals_ && conf_has_signal_sources_ && conf_has_observables_ && conf_has_pvt_; + restart_ = false; init(); } @@ -91,6 +126,12 @@ ControlThread::ControlThread() ControlThread::ControlThread(std::shared_ptr configuration) { configuration_ = std::move(configuration); + conf_file_has_section_ = true; + conf_file_has_mandatory_globals_ = true; + conf_has_signal_sources_ = true; + conf_has_observables_ = true; + conf_has_pvt_ = true; + well_formatted_configuration_ = true; restart_ = false; init(); } @@ -104,14 +145,22 @@ void ControlThread::init() // Instantiates a control queue, a GNSS flowgraph, and a control message factory control_queue_ = std::make_shared>(); cmd_interface_.set_msg_queue(control_queue_); // set also the queue pointer for the telecommand thread - try + if (well_formatted_configuration_) { - flowgraph_ = std::make_shared(configuration_, control_queue_); + try + { + flowgraph_ = std::make_shared(configuration_, control_queue_); + } + catch (const boost::bad_lexical_cast &e) + { + std::cout << "Caught bad lexical cast with error " << e.what() << '\n'; + } } - catch (const boost::bad_lexical_cast &e) + else { - std::cout << "Caught bad lexical cast with error " << e.what() << '\n'; + flowgraph_ = nullptr; } + stop_ = false; processed_control_messages_ = 0; applied_actions_ = 0; @@ -285,6 +334,11 @@ void ControlThread::event_dispatcher(bool &valid_event, pmt::pmt_t &msg) int ControlThread::run() { // Connect the flowgraph + if (!flowgraph_) + { + print_help_at_exit(); + return 0; + } try { flowgraph_->connect(); @@ -1145,3 +1199,37 @@ void ControlThread::keyboard_listener() } } } + + +void ControlThread::print_help_at_exit() const +{ + std::cerr << "Error: the configuration file is not well formatted\n"; + if (!conf_file_has_section_) + { + std::cerr << " * The section label has not been found if the configuration file\n" + << " Please add the [GNSS-SDR] label at the top of your configuration file\n" + << " A configuration example is available at https://gnss-sdr.org/my-first-fix/\n"; + return; + } + if (!conf_file_has_mandatory_globals_) + { + std::cerr << " * Have you forgotten to set the mandatory global parameter GNSS-SDR.internal_fs_sps in your conf file?\n" + << " Documentation about this parameter at https://gnss-sdr.org/docs/sp-blocks/global-parameters/\n" + << " A configuration example is available at https://gnss-sdr.org/my-first-fix/\n"; + } + if (!conf_has_signal_sources_) + { + std::cerr << " * The configuration file must define at least one SignalSource.implementation\n" + << " Documentation of SignalSource block implementations at https://gnss-sdr.org/docs/sp-blocks/signal-source/\n"; + } + if (!conf_has_observables_) + { + std::cerr << " * The configuration file must define an Observables.implementation\n" + << " Documentation of the Observables block at https://gnss-sdr.org/docs/sp-blocks/observables/\n"; + } + if (!conf_has_pvt_) + { + std::cerr << " * The configuration file must define a PVT.implementation\n" + << " Documentation of the PVT block at https://gnss-sdr.org/docs/sp-blocks/pvt/\n"; + } +} diff --git a/src/core/receiver/control_thread.h b/src/core/receiver/control_thread.h index e28271725..12f6fbc49 100644 --- a/src/core/receiver/control_thread.h +++ b/src/core/receiver/control_thread.h @@ -153,6 +153,7 @@ private: void telecommand_listener(); void keyboard_listener(); void sysv_queue_listener(); + void print_help_at_exit() const; // default filename for assistance data const std::string eph_default_xml_filename_ = "./gps_ephemeris.xml"; @@ -203,6 +204,12 @@ private: unsigned int applied_actions_; int msqid_; + bool well_formatted_configuration_; + bool conf_file_has_section_; + bool conf_file_has_mandatory_globals_; + bool conf_has_signal_sources_; + bool conf_has_observables_; + bool conf_has_pvt_; bool receiver_on_standby_; bool stop_; bool restart_; diff --git a/src/core/receiver/file_configuration.cc b/src/core/receiver/file_configuration.cc index b8cd47154..53700a21c 100644 --- a/src/core/receiver/file_configuration.cc +++ b/src/core/receiver/file_configuration.cc @@ -60,6 +60,12 @@ void FileConfiguration::init() } +bool FileConfiguration::has_section() const +{ + return ini_reader_->HasSection("GNSS-SDR"); +} + + std::string FileConfiguration::property(std::string property_name, std::string default_value) const { if (overrided_->is_present(property_name)) diff --git a/src/core/receiver/file_configuration.h b/src/core/receiver/file_configuration.h index 9b79b2374..1af476913 100644 --- a/src/core/receiver/file_configuration.h +++ b/src/core/receiver/file_configuration.h @@ -63,6 +63,7 @@ public: double property(std::string property_name, double default_value) const override; void set_property(std::string property_name, std::string value) override; bool is_present(const std::string& property_name) const; + bool has_section() const; private: void init(); From 2f627581ef794582ff05d4fc0034a8c4ea41c2d8 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 25 Jan 2021 13:35:47 +0100 Subject: [PATCH 04/12] Fix error handling issues detected by Coverity Scan 2020.09 --- .../PVT/libs/monitor_pvt_udp_sink.cc | 5 +++- .../two_bit_packed_file_signal_source.cc | 3 +- .../signal_source/libs/rtl_tcp_commands.cc | 5 +++- .../signal_source/libs/rtl_tcp_dongle_info.cc | 6 ++-- .../tracking/libs/tcp_communication.cc | 24 ++++++++++++--- src/core/monitor/gnss_synchro_udp_sink.cc | 6 +++- src/core/receiver/tcp_cmd_interface.cc | 29 ++++++++++++------- 7 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc index 240ee419d..0d54d6bcd 100644 --- a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc +++ b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc @@ -59,7 +59,10 @@ bool Monitor_Pvt_Udp_Sink::write_monitor_pvt(const Monitor_Pvt* const monitor_pv try { - socket.send(boost::asio::buffer(outbound_data)); + if (socket.send(boost::asio::buffer(outbound_data)) == 0) + { + return false; + } } catch (boost::system::system_error const& e) { 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 ed43e34c8..c31bf3390 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 @@ -92,6 +92,8 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource( item_size_ = sizeof(char); } + reverse_interleaving_ = false; + is_complex_ = true; if (sample_type_ == "real") { is_complex_ = false; @@ -99,7 +101,6 @@ TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource( else if (sample_type_ == "iq") { is_complex_ = true; - reverse_interleaving_ = false; } else if (sample_type_ == "qi") { diff --git a/src/algorithms/signal_source/libs/rtl_tcp_commands.cc b/src/algorithms/signal_source/libs/rtl_tcp_commands.cc index b1685adf7..5ba7320fa 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_commands.cc +++ b/src/algorithms/signal_source/libs/rtl_tcp_commands.cc @@ -32,6 +32,9 @@ boost::system::error_code rtl_tcp_command(RTL_TCP_COMMAND id, unsigned param, bo std::memcpy(&data[1], &nparam, sizeof(nparam)); boost::system::error_code ec; - socket.send(boost::asio::buffer(data), 0, ec); + if (socket.send(boost::asio::buffer(data), 0, ec) == 0) + { + // 0 bytes sent + } return ec; } diff --git a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc index eafb05f6c..8bacdee8a 100644 --- a/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc +++ b/src/algorithms/signal_source/libs/rtl_tcp_dongle_info.cc @@ -35,8 +35,8 @@ boost::system::error_code Rtl_Tcp_Dongle_Info::read(boost::asio::ip::tcp::socket boost::system::error_code ec; unsigned char data[sizeof(char) * 4 + sizeof(uint32_t) * 2]; - socket.receive(boost::asio::buffer(data), 0, ec); - if (!ec) + size_t received_bits = socket.receive(boost::asio::buffer(data), 0, ec); + if (!ec && (received_bits > 0)) { std::memcpy(magic_, data, 4); @@ -46,7 +46,7 @@ boost::system::error_code Rtl_Tcp_Dongle_Info::read(boost::asio::ip::tcp::socket tuner_type_ = boost::asio::detail::socket_ops::network_to_host_long(type); uint32_t count; - std ::memcpy(&count, &data[8], 4); + std::memcpy(&count, &data[8], 4); tuner_gain_count_ = boost::asio::detail::socket_ops::network_to_host_long(count); } diff --git a/src/algorithms/tracking/libs/tcp_communication.cc b/src/algorithms/tracking/libs/tcp_communication.cc index 4ca44e734..17cd20c09 100644 --- a/src/algorithms/tracking/libs/tcp_communication.cc +++ b/src/algorithms/tracking/libs/tcp_communication.cc @@ -66,10 +66,16 @@ void Tcp_Communication::send_receive_tcp_packet_galileo_e1(boost::array> controlc; } + catch (...) + { + std::cerr << "Exception reading TCP data\n"; + } } diff --git a/src/core/monitor/gnss_synchro_udp_sink.cc b/src/core/monitor/gnss_synchro_udp_sink.cc index fa1216433..3eb61578d 100644 --- a/src/core/monitor/gnss_synchro_udp_sink.cc +++ b/src/core/monitor/gnss_synchro_udp_sink.cc @@ -57,10 +57,14 @@ bool Gnss_Synchro_Udp_Sink::write_gnss_synchro(const std::vector& try { - socket.send(boost::asio::buffer(outbound_data)); + if (socket.send(boost::asio::buffer(outbound_data)) == 0) + { + std::cerr << "Gnss_Synchro_Udp_Sink sent 0 bytes\n"; + } } catch (boost::system::system_error const& e) { + std::cerr << e.what() << '\n'; return false; } } diff --git a/src/core/receiver/tcp_cmd_interface.cc b/src/core/receiver/tcp_cmd_interface.cc index 0c60f00e5..d18a2da62 100644 --- a/src/core/receiver/tcp_cmd_interface.cc +++ b/src/core/receiver/tcp_cmd_interface.cc @@ -326,7 +326,7 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) acceptor.accept(socket, not_throw); if (not_throw) { - std::cout << "TcpCmdInterface: Error when binding the port in the socket\n"; + std::cerr << "TcpCmdInterface: Error when binding the port in the socket\n"; continue; } @@ -336,7 +336,10 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) { std::string response; boost::asio::streambuf b; - boost::asio::read_until(socket, b, '\n', error); + if (boost::asio::read_until(socket, b, '\n', error) == 0) + { + std::cerr << "TcpCmdInterface: Error reading messages: " << error.message() << '\n'; + } std::istream is(&b); std::string line; std::getline(is, line); @@ -352,7 +355,10 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) { error = boost::asio::error::eof; // send cmd response - socket.write_some(boost::asio::buffer("OK\n"), not_throw); + if (socket.write_some(boost::asio::buffer("OK\n"), not_throw) == 0) + { + std::cerr << "Error: 0 bytes sent in cmd response\n"; + } } else { @@ -374,10 +380,13 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) } // send cmd response - socket.write_some(boost::asio::buffer(response), not_throw); + if (socket.write_some(boost::asio::buffer(response), not_throw) == 0) + { + std::cerr << "Error: 0 bytes sent in cmd response\n"; + } if (not_throw) { - std::cout << "Error sending(" << not_throw.value() << "): " << not_throw.message() << '\n'; + std::cerr << "Error sending(" << not_throw.value() << "): " << not_throw.message() << '\n'; break; } } @@ -385,11 +394,11 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) if (error == boost::asio::error::eof) { - std::cout << "TcpCmdInterface: EOF detected\n"; + std::cerr << "TcpCmdInterface: EOF detected\n"; } else { - std::cout << "TcpCmdInterface unexpected error: " << error << '\n'; + std::cerr << "TcpCmdInterface unexpected error: " << error << '\n'; } // Close socket @@ -397,16 +406,16 @@ void TcpCmdInterface::run_cmd_server(int tcp_port) } catch (const boost::exception &e) { - std::cout << "TcpCmdInterface: Boost exception\n"; + std::cerr << "TcpCmdInterface: Boost exception\n"; } catch (const std::exception &ex) { - std::cout << "TcpCmdInterface: Exception " << ex.what() << '\n'; + std::cerr << "TcpCmdInterface: Exception " << ex.what() << '\n'; } } } catch (const boost::exception &e) { - std::cout << "TCP Command Interface exception: address already in use\n"; + std::cerr << "TCP Command Interface exception: address already in use\n"; } } From d6d1fff743951a1393fcc00e9523bb91eaf49a7f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 25 Jan 2021 22:07:59 +0100 Subject: [PATCH 05/12] Apply clang-tidy fixes when -DENABLE_FPGA=ON --- .../signal_source/libs/fpga_dynamic_bit_selection.cc | 2 +- .../gnuradio_blocks/dll_pll_veml_tracking_fpga.cc | 2 +- .../gnuradio_blocks/dll_pll_veml_tracking_fpga.h | 2 +- src/algorithms/tracking/libs/fpga_multicorrelator.cc | 2 +- src/algorithms/tracking/libs/fpga_multicorrelator.h | 2 +- src/core/libs/uio_fpga.cc | 9 ++++++--- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc index 583fbfe0c..1802324c5 100644 --- a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc +++ b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc @@ -69,7 +69,7 @@ Fpga_dynamic_bit_selection::~Fpga_dynamic_bit_selection() } -void Fpga_dynamic_bit_selection::bit_selection(void) +void Fpga_dynamic_bit_selection::bit_selection() { // estimated signal power corresponding to frequency band 1 uint32_t rx_signal_power1 = d_map_base1[1]; diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc index b0192f26e..c5b224f5f 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc @@ -1297,7 +1297,7 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() const } -void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel, std::string device_io_name) +void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel, const std::string& device_io_name) { gr::thread::scoped_lock l(d_setlock); diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h index 9233f2715..3a2c863a9 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h @@ -66,7 +66,7 @@ public: /*! * \brief Set the channel number and configure some multicorrelator parameters */ - void set_channel(uint32_t channel, std::string device_io_name); + void set_channel(uint32_t channel, const std::string& device_io_name); /*! * \brief This function is used with two purposes: diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.cc b/src/algorithms/tracking/libs/fpga_multicorrelator.cc index a962dfbe1..edb87a375 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.cc +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.cc @@ -192,7 +192,7 @@ bool Fpga_Multicorrelator_8sc::free() } -void Fpga_Multicorrelator_8sc::open_channel(std::string device_io_name, uint32_t channel) +void Fpga_Multicorrelator_8sc::open_channel(const std::string& device_io_name, uint32_t channel) { std::cout << "trk device_io_name = " << device_io_name << '\n'; diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.h b/src/algorithms/tracking/libs/fpga_multicorrelator.h index f67520f63..42fa151b9 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.h +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.h @@ -91,7 +91,7 @@ public: /*! * \brief Open the FPGA device driver */ - void open_channel(std::string device_io_name, uint32_t channel); + void open_channel(const std::string& device_io_name, uint32_t channel); /*! * \brief Set the initial sample number where the tracking process begins diff --git a/src/core/libs/uio_fpga.cc b/src/core/libs/uio_fpga.cc index 14156a654..647ec846e 100644 --- a/src/core/libs/uio_fpga.cc +++ b/src/core/libs/uio_fpga.cc @@ -32,7 +32,10 @@ int32_t get_uio_num(std::string uio_name) // search first digit for (; i < uio_name.length(); i++) { - if (isdigit(uio_name[i])) break; + if (isdigit(uio_name[i])) + { + break; + } } // remove the first chars, which aren't digits @@ -137,7 +140,7 @@ int my_strverscmp(const char *s1, const char *s2) } -bool sort_directories(fs::directory_entry a, fs::directory_entry b) +bool sort_directories(const fs::directory_entry &a, const fs::directory_entry &b) { int cmp = my_strverscmp(a.path().string().c_str(), b.path().string().c_str()); return (cmp < 0); @@ -166,7 +169,7 @@ int32_t find_uio_num(const std::string &device_name, uint32_t device_num) { std::string nametemp; get_uio_name(uio_num, nametemp); - if (device_name.compare(nametemp) == 0) + if (device_name == nametemp) { if (uio_count == device_num) { From 950111d0fe6a9024a64c47e1789556b352c9cc45 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 25 Jan 2021 22:19:18 +0100 Subject: [PATCH 06/12] Avoid warning when building googletest with CMake >= 3.19 --- src/tests/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 69f3629d6..8b9c181de 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -63,9 +63,15 @@ if(NOT GOOGLETEST_FOUND) ${CMAKE_BINARY_DIR}/gtest-${GNSSSDR_GTEST_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_maind${CMAKE_STATIC_LIBRARY_SUFFIX} ) endif() + set(GOOGLETEST_GIT_TAG "v1.10.x") + if(CMAKE_VERSION VERSION_GREATER 3.18.99) + # workaround to avoid warning about deprecated CMakeLists.txt with CMake >= 3.19 + # Remove after a stable release of Googletest including this fix + set(GOOGLETEST_GIT_TAG "d128fc8252d53baad6ea456fa08cbf9028d255f4") + endif() ExternalProject_Add(gtest-${GNSSSDR_GTEST_LOCAL_VERSION} GIT_REPOSITORY https://github.com/google/googletest - GIT_TAG v1.10.x + GIT_TAG ${GOOGLETEST_GIT_TAG} SOURCE_DIR ${CMAKE_BINARY_DIR}/thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} BINARY_DIR ${CMAKE_BINARY_DIR}/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} CMAKE_ARGS ${GTEST_COMPILER} From d738d893c644868c2f021de294b4a8f71cef9ea1 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 00:14:50 +0100 Subject: [PATCH 07/12] Apply clang-format --- .../tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc | 2 +- .../tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h | 2 +- src/algorithms/tracking/libs/fpga_multicorrelator.cc | 2 +- src/algorithms/tracking/libs/fpga_multicorrelator.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc index c5b224f5f..0b65723cc 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc @@ -1297,7 +1297,7 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() const } -void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel, const std::string& device_io_name) +void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel, const std::string &device_io_name) { gr::thread::scoped_lock l(d_setlock); diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h index 3a2c863a9..d00385fb9 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h @@ -66,7 +66,7 @@ public: /*! * \brief Set the channel number and configure some multicorrelator parameters */ - void set_channel(uint32_t channel, const std::string& device_io_name); + void set_channel(uint32_t channel, const std::string &device_io_name); /*! * \brief This function is used with two purposes: diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.cc b/src/algorithms/tracking/libs/fpga_multicorrelator.cc index edb87a375..3ca164ed8 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.cc +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.cc @@ -192,7 +192,7 @@ bool Fpga_Multicorrelator_8sc::free() } -void Fpga_Multicorrelator_8sc::open_channel(const std::string& device_io_name, uint32_t channel) +void Fpga_Multicorrelator_8sc::open_channel(const std::string &device_io_name, uint32_t channel) { std::cout << "trk device_io_name = " << device_io_name << '\n'; diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.h b/src/algorithms/tracking/libs/fpga_multicorrelator.h index 42fa151b9..58e554f14 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.h +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.h @@ -91,7 +91,7 @@ public: /*! * \brief Open the FPGA device driver */ - void open_channel(const std::string& device_io_name, uint32_t channel); + void open_channel(const std::string &device_io_name, uint32_t channel); /*! * \brief Set the initial sample number where the tracking process begins From 7f23b6d88bfc10c1bb2a87ac791def83529d5032 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 11:58:46 +0100 Subject: [PATCH 08/12] Use C++ cast insted of C-style cast --- src/core/libs/uio_fpga.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libs/uio_fpga.cc b/src/core/libs/uio_fpga.cc index 647ec846e..c8a143a90 100644 --- a/src/core/libs/uio_fpga.cc +++ b/src/core/libs/uio_fpga.cc @@ -82,8 +82,8 @@ int my_strverscmp(const char *s1, const char *s2) const int8_t CMP = 2; const int8_t LEN = 3; - const unsigned char *p1 = (const unsigned char *)s1; - const unsigned char *p2 = (const unsigned char *)s2; + const auto *p1 = reinterpret_cast(s1); + const auto *p2 = reinterpret_cast(s2); /* Symbol(s) 0 [1-9] others Transition (10) 0 (01) d (00) x */ static const uint8_t next_state[] = From 862bdeea5c0b5b91c6ce8c95bb48a350cc378ad7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 14:01:28 +0100 Subject: [PATCH 09/12] Avoid segmentation fault if the Tracking item_type is not defined for the given implementation --- src/algorithms/channel/adapters/channel.cc | 10 +++++++++- .../tracking/adapters/beidou_b1i_dll_pll_tracking.cc | 2 +- .../tracking/adapters/beidou_b3i_dll_pll_tracking.cc | 2 +- .../adapters/galileo_e1_dll_pll_veml_tracking.cc | 2 +- .../adapters/galileo_e1_tcp_connector_tracking.cc | 2 +- .../tracking/adapters/galileo_e5a_dll_pll_tracking.cc | 2 +- .../tracking/adapters/galileo_e5b_dll_pll_tracking.cc | 2 +- .../tracking/adapters/galileo_e6_dll_pll_tracking.cc | 2 +- .../adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc | 2 +- .../adapters/glonass_l1_ca_dll_pll_tracking.cc | 2 +- .../adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc | 2 +- .../adapters/glonass_l2_ca_dll_pll_tracking.cc | 2 +- .../tracking/adapters/gps_l1_ca_dll_pll_tracking.cc | 2 +- .../adapters/gps_l1_ca_dll_pll_tracking_gpu.cc | 2 +- .../tracking/adapters/gps_l1_ca_kf_tracking.cc | 2 +- .../adapters/gps_l1_ca_tcp_connector_tracking.cc | 2 +- .../tracking/adapters/gps_l2_m_dll_pll_tracking.cc | 2 +- .../tracking/adapters/gps_l5_dll_pll_tracking.cc | 2 +- src/core/receiver/gnss_block_factory.cc | 5 +++++ src/core/receiver/gnss_flowgraph.cc | 2 +- 20 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/algorithms/channel/adapters/channel.cc b/src/algorithms/channel/adapters/channel.cc index 176e2983c..2c9d54387 100644 --- a/src/algorithms/channel/adapters/channel.cc +++ b/src/algorithms/channel/adapters/channel.cc @@ -23,7 +23,8 @@ #include "telemetry_decoder_interface.h" #include "tracking_interface.h" #include -#include // for std::move +#include // for std::invalid_argument +#include // for std::move Channel::Channel(const ConfigurationInterface* configuration, @@ -113,6 +114,13 @@ void Channel::connect(gr::top_block_sptr top_block) acq_->connect(top_block); } trk_->connect(top_block); + + if (trk_->item_size() == 0) + { + std::string msg = trk_->role() + ".item_type is not defined for implementation " + trk_->implementation() + '\n'; + throw std::invalid_argument(msg); + } + nav_->connect(top_block); // Synchronous ports diff --git a/src/algorithms/tracking/adapters/beidou_b1i_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/beidou_b1i_dll_pll_tracking.cc index b9ca4f26f..ec7b2b503 100644 --- a/src/algorithms/tracking/adapters/beidou_b1i_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/beidou_b1i_dll_pll_tracking.cc @@ -72,7 +72,7 @@ BeidouB1iDllPllTracking::BeidouB1iDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/beidou_b3i_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/beidou_b3i_dll_pll_tracking.cc index 50d7e7db9..8d7eb3487 100644 --- a/src/algorithms/tracking/adapters/beidou_b3i_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/beidou_b3i_dll_pll_tracking.cc @@ -64,7 +64,7 @@ BeidouB3iDllPllTracking::BeidouB3iDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc index e9de4c014..d77519495 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking.cc @@ -65,7 +65,7 @@ GalileoE1DllPllVemlTracking::GalileoE1DllPllVemlTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } diff --git a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc index 6ce6613fb..d4c4c8340 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e1_tcp_connector_tracking.cc @@ -74,7 +74,7 @@ GalileoE1TcpConnectorTracking::GalileoE1TcpConnectorTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc index 38a88833e..b954a800a 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking.cc @@ -65,7 +65,7 @@ GalileoE5aDllPllTracking::GalileoE5aDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/galileo_e5b_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/galileo_e5b_dll_pll_tracking.cc index ef072c0ff..a77999ff1 100644 --- a/src/algorithms/tracking/adapters/galileo_e5b_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e5b_dll_pll_tracking.cc @@ -66,7 +66,7 @@ GalileoE5bDllPllTracking::GalileoE5bDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/galileo_e6_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/galileo_e6_dll_pll_tracking.cc index 5fb8dfa82..d123ca2d3 100644 --- a/src/algorithms/tracking/adapters/galileo_e6_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/galileo_e6_dll_pll_tracking.cc @@ -61,7 +61,7 @@ GalileoE6DllPllTracking::GalileoE6DllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc index 3f5814abd..3cb81f43c 100644 --- a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc @@ -95,7 +95,7 @@ GlonassL1CaDllPllCAidTracking::GlonassL1CaDllPllCAidTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type_ << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc index 4d34b8da2..253f82774 100644 --- a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc @@ -70,7 +70,7 @@ GlonassL1CaDllPllTracking::GlonassL1CaDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc index 061d2a064..1cd2f6cf1 100644 --- a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_c_aid_tracking.cc @@ -93,7 +93,7 @@ GlonassL2CaDllPllCAidTracking::GlonassL2CaDllPllCAidTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type_ << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc index 1d6759676..0ce3c1291 100644 --- a/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l2_ca_dll_pll_tracking.cc @@ -68,7 +68,7 @@ GlonassL2CaDllPllTracking::GlonassL2CaDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc index 768888b12..7c35a1e3c 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking.cc @@ -73,7 +73,7 @@ GpsL1CaDllPllTracking::GpsL1CaDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc index 94001c8bd..0060b2ee1 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_gpu.cc @@ -72,7 +72,7 @@ GpsL1CaDllPllTrackingGPU::GpsL1CaDllPllTrackingGPU( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc index bba2cb308..a34cf388b 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_kf_tracking.cc @@ -81,7 +81,7 @@ GpsL1CaKfTracking::GpsL1CaKfTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc index 4360ba61f..eb1ee936e 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_tcp_connector_tracking.cc @@ -60,7 +60,7 @@ GpsL1CaTcpConnectorTracking::GpsL1CaTcpConnectorTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << item_type << " unknown tracking item type."; } diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc index fdfd11948..9c1b5aadd 100644 --- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking.cc @@ -62,7 +62,7 @@ GpsL2MDllPllTracking::GpsL2MDllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc index e14a01327..bea9b5b25 100644 --- a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking.cc @@ -65,7 +65,7 @@ GpsL5DllPllTracking::GpsL5DllPllTracking( } else { - item_size_ = sizeof(gr_complex); + item_size_ = 0; LOG(WARNING) << trk_params.item_type << " unknown tracking item type."; } channel_ = 0; diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 67ab07687..581ac7771 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -393,6 +393,11 @@ std::unique_ptr GNSSBlockFactory::GetChannel( { return nullptr; } + if (trk_->item_size() == 0) + { + LOG(ERROR) << trk_->role() << ".item_type=" << acq_item_type << " is not defined for implementation " << trk_->implementation(); + return nullptr; + } std::unique_ptr channel_ = std::make_unique(configuration, channel, std::move(acq_), diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index d37970fbd..db7e7eeac 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -804,7 +804,7 @@ int GNSSFlowgraph::connect_channels() else { LOG(ERROR) << "Can't connect channel " << i << " internally"; - help_hint_ += " * Check implementation names for Channel" + std::to_string(i) + " inner blocks.\n"; + help_hint_ += " * Check your configuration for Channel" + std::to_string(i) + " inner blocks.\n"; help_hint_ += " Acquisition blocks documentation at https://gnss-sdr.org/docs/sp-blocks/acquisition/\n"; help_hint_ += " Tracking blocks documentation at https://gnss-sdr.org/docs/sp-blocks/tracking/\n"; help_hint_ += " Telemetry Decoder blocks documentation at https://gnss-sdr.org/docs/sp-blocks/telemetry-decoder/\n"; From 720215af3061aaa80e50658f92cc666c7e255782 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 15:20:37 +0100 Subject: [PATCH 10/12] Avoid segmentation fault if the item_type for the signal source is mismatched with the input item size of the Signal Conditioner --- src/core/receiver/gnss_flowgraph.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index db7e7eeac..2e3666246 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -1039,10 +1039,19 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() { // Connect the multichannel signal source to multiple signal conditioners // GNURADIO max_streams=-1 means infinite ports! - DLOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); - DLOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); size_t output_size = sig_source_.at(i)->item_size(); size_t input_size = sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->sizeof_stream_item(0); + // Check configuration inconsistencies + if (output_size != input_size) + { + help_hint_ += " * The Signal Source implementation " + sig_source_.at(i)->implementation() + " has an output with a "; + help_hint_ += sig_source_.at(i)->role() + ".item_size of " + std::to_string(output_size); + help_hint_ += " bytes, but it is connected to the Signal Conditioner implementation "; + help_hint_ += sig_conditioner_.at(signal_conditioner_ID)->implementation() + " with input item size of " + std::to_string(input_size) + " bytes.\n"; + help_hint_ += " Output ports must be connected to input ports with the same item size.\n"; + top_block_->disconnect_all(); + return 1; + } if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) { @@ -1068,12 +1077,6 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() } } signal_conditioner_ID++; - // Check configuration inconsistencies - if (output_size != input_size) - { - help_hint_ += " * The Signal Source implementation " + sig_source_.at(i)->implementation() + " has an output with an item size of " + std::to_string(output_size) + " bytes, but it is connected to the Signal Conditioner implementation " + sig_conditioner_.at(signal_conditioner_ID)->implementation() + " with input item size of " + std::to_string(input_size) + "bytes.\n"; - help_hint_ += " Output ports must be connected to input ports with the same item size.\n"; - } } } } From 24041058a6c077f2cdb97d4c613cab2a87cc137f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 16:11:41 +0100 Subject: [PATCH 11/12] Improve reported output in case of configuration error --- src/algorithms/libs/pass_through.cc | 17 +++-------------- src/core/receiver/gnss_flowgraph.cc | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/algorithms/libs/pass_through.cc b/src/algorithms/libs/pass_through.cc index b5b7d2039..dbc96f32e 100644 --- a/src/algorithms/libs/pass_through.cc +++ b/src/algorithms/libs/pass_through.cc @@ -32,16 +32,7 @@ Pass_Through::Pass_Through(const ConfigurationInterface* configuration, const st out_streams_(out_streams) { const std::string default_item_type("gr_complex"); - const std::string input_type = configuration->property(role + ".input_item_type", default_item_type); - const std::string output_type = configuration->property(role + ".output_item_type", default_item_type); - if (input_type != output_type) - { - LOG(WARNING) << "input_item_type and output_item_type are different in a Pass_Through implementation! Taking " - << input_type - << ", but item_size will supersede it."; - } - - item_type_ = configuration->property(role + ".item_type", input_type); + item_type_ = configuration->property(role + ".item_type", default_item_type); inverted_spectrum = configuration->property(role + ".inverted_spectrum", false); if (item_type_ == "float") @@ -96,13 +87,11 @@ Pass_Through::Pass_Through(const ConfigurationInterface* configuration, const st DLOG(INFO) << "kludge_copy(" << kludge_copy_->unique_id() << ")"; if (in_streams_ > 1) { - LOG(ERROR) << "This implementation only supports one input stream"; - LOG(ERROR) << in_streams_; + LOG(ERROR) << "This implementation only supports one input stream but it is set to " << in_streams_; } if (out_streams_ > 1) { - LOG(ERROR) << "This implementation only supports one output stream"; - LOG(ERROR) << out_streams_; + LOG(ERROR) << "This implementation only supports one output stream but it is set to " << out_streams_; } } diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 2e3666246..967c50807 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -736,9 +736,13 @@ int GNSSFlowgraph::connect_signal_conditioners() { std::string replace_me("copy"); size_t pos = reported_error.find(replace_me); - size_t len = replace_me.length(); - reported_error.replace(pos, len, "PassThrough"); - help_hint_ += " * Blocks within the Signal Conditioner are connected with mismatched item size\n"; + while (pos != std::string::npos) + { + size_t len = replace_me.length(); + reported_error.replace(pos, len, "Pass_Through"); + pos = reported_error.find(replace_me, pos + 1); + } + help_hint_ += " * Blocks within the Signal Conditioner are connected with mismatched input/ouput item size\n"; help_hint_ += " Reported error: " + reported_error + '\n'; help_hint_ += " Check the Signal Conditioner documentation at https://gnss-sdr.org/docs/sp-blocks/signal-conditioner/\n"; } @@ -1088,8 +1092,12 @@ int GNSSFlowgraph::connect_signal_sources_to_signal_conditioners() { std::string replace_me("copy"); size_t pos = reported_error.find(replace_me); - size_t len = replace_me.length(); - reported_error.replace(pos, len, "PassThrough"); + while (pos != std::string::npos) + { + size_t len = replace_me.length(); + reported_error.replace(pos, len, "Pass_Through"); + pos = reported_error.find(replace_me, pos + 1); + } help_hint_ += " * The SignalSource output item size and the SignalConditioner input item size are mismatched\n"; help_hint_ += " Reported error: " + reported_error + '\n'; } From d249a7efcf3376039c3112729cc4811cc7080b54 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 26 Jan 2021 23:11:06 +0100 Subject: [PATCH 12/12] Avoid segmentation faults if the SignalConditioner is not well defined in the configuration --- .../adapters/signal_conditioner.cc | 20 +++++++++++++++++ .../adapters/beamformer_filter.cc | 2 +- .../adapters/freq_xlating_fir_filter.cc | 4 ++-- .../input_filter/adapters/notch_filter.cc | 2 +- .../adapters/notch_filter_lite.cc | 2 +- .../adapters/pulse_blanking_filter.cc | 22 +++++++++---------- .../adapters/pulse_blanking_filter.h | 3 +-- src/core/receiver/gnss_flowgraph.cc | 18 +++++++++++++-- 8 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/algorithms/conditioner/adapters/signal_conditioner.cc b/src/algorithms/conditioner/adapters/signal_conditioner.cc index 7ffec8148..fcac05a40 100644 --- a/src/algorithms/conditioner/adapters/signal_conditioner.cc +++ b/src/algorithms/conditioner/adapters/signal_conditioner.cc @@ -57,6 +57,26 @@ void SignalConditioner::connect(gr::top_block_sptr top_block) in_filt_->connect(top_block); res_->connect(top_block); + if (in_filt_->item_size() == 0) + { + throw std::invalid_argument("itemsize mismatch: Invalid input/ouput data type configuration for the InputFilter"); + } + + const size_t data_type_adapter_output_size = data_type_adapt_->get_right_block()->output_signature()->sizeof_stream_item(0); + const size_t input_filter_input_size = in_filt_->get_left_block()->input_signature()->sizeof_stream_item(0); + const size_t input_filter_output_size = in_filt_->get_right_block()->output_signature()->sizeof_stream_item(0); + const size_t resampler_input_size = res_->get_left_block()->input_signature()->sizeof_stream_item(0); + + if (data_type_adapter_output_size != input_filter_input_size) + { + throw std::invalid_argument("itemsize mismatch: Invalid input/ouput data type configuration for the DataTypeAdapter/InputFilter connection"); + } + + if (input_filter_output_size != resampler_input_size) + { + throw std::invalid_argument("itemsize mismatch: Invalid input/ouput data type configuration for the Input Filter/Resampler connection"); + } + top_block->connect(data_type_adapt_->get_right_block(), 0, in_filt_->get_left_block(), 0); DLOG(INFO) << "data_type_adapter -> input_filter"; diff --git a/src/algorithms/input_filter/adapters/beamformer_filter.cc b/src/algorithms/input_filter/adapters/beamformer_filter.cc index 69b7d60a9..3d8707e20 100644 --- a/src/algorithms/input_filter/adapters/beamformer_filter.cc +++ b/src/algorithms/input_filter/adapters/beamformer_filter.cc @@ -43,7 +43,7 @@ BeamformerFilter::BeamformerFilter( { LOG(WARNING) << item_type_ << " unrecognized item type for beamformer"; - item_size_ = sizeof(gr_complex); + item_size_ = 0; } if (dump_) { diff --git a/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc b/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc index dd504101a..73b6b9381 100644 --- a/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc +++ b/src/algorithms/input_filter/adapters/freq_xlating_fir_filter.cc @@ -159,8 +159,8 @@ FreqXlatingFirFilter::FreqXlatingFirFilter(const ConfigurationInterface* configu else { LOG(ERROR) << " Unknown input filter input/output item type conversion"; - item_size = sizeof(gr_complex); // avoids uninitialization - input_size_ = sizeof(gr_complex); // avoids uninitialization + item_size = sizeof(gr_complex); // avoids uninitialization + input_size_ = 0; // notifies wrong configuration } if (dump_) diff --git a/src/algorithms/input_filter/adapters/notch_filter.cc b/src/algorithms/input_filter/adapters/notch_filter.cc index 1d9f5ea98..c3f1dfd0a 100644 --- a/src/algorithms/input_filter/adapters/notch_filter.cc +++ b/src/algorithms/input_filter/adapters/notch_filter.cc @@ -51,7 +51,7 @@ NotchFilter::NotchFilter(const ConfigurationInterface* configuration, const std: else { LOG(WARNING) << item_type_ << " unrecognized item type for notch filter"; - item_size_ = sizeof(gr_complex); + item_size_ = 0; // notify wrong configuration } if (dump_) { diff --git a/src/algorithms/input_filter/adapters/notch_filter_lite.cc b/src/algorithms/input_filter/adapters/notch_filter_lite.cc index 562bff514..530085a24 100644 --- a/src/algorithms/input_filter/adapters/notch_filter_lite.cc +++ b/src/algorithms/input_filter/adapters/notch_filter_lite.cc @@ -58,7 +58,7 @@ NotchFilterLite::NotchFilterLite(const ConfigurationInterface* configuration, co else { LOG(WARNING) << item_type_ << " unrecognized item type for notch filter"; - item_size_ = sizeof(gr_complex); + item_size_ = 0; } if (dump_) { diff --git a/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc b/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc index 3c82314d8..f22ab676e 100644 --- a/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc +++ b/src/algorithms/input_filter/adapters/pulse_blanking_filter.cc @@ -31,14 +31,12 @@ PulseBlankingFilter::PulseBlankingFilter(const ConfigurationInterface* configura { size_t item_size; xlat_ = false; - const std::string default_input_item_type("gr_complex"); - const std::string default_output_item_type("gr_complex"); + const std::string default_item_type("gr_complex"); const std::string default_dump_filename("../data/input_filter.dat"); DLOG(INFO) << "role " << role_; - input_item_type_ = configuration->property(role_ + ".input_item_type", default_input_item_type); - output_item_type_ = configuration->property(role_ + ".output_item_type", default_output_item_type); + item_type_ = configuration->property(role_ + ".item_type", default_item_type); dump_ = configuration->property(role_ + ".dump", false); dump_filename_ = configuration->property(role_ + ".dump_filename", default_dump_filename); const float default_pfa_ = 0.04; @@ -49,7 +47,7 @@ PulseBlankingFilter::PulseBlankingFilter(const ConfigurationInterface* configura const int n_segments_est = configuration->property(role_ + ".segments_est", default_n_segments_est); const int default_n_segments_reset = 5000000; const int n_segments_reset = configuration->property(role_ + ".segments_reset", default_n_segments_reset); - if (input_item_type_ == "gr_complex") + if (item_type_ == "gr_complex") { item_size = sizeof(gr_complex); // output input_size_ = sizeof(gr_complex); // input @@ -57,9 +55,9 @@ PulseBlankingFilter::PulseBlankingFilter(const ConfigurationInterface* configura } else { - LOG(ERROR) << " Unknown input filter input/output item type conversion"; - item_size = sizeof(gr_complex); // avoids uninitialization - input_size_ = sizeof(gr_complex); // avoids uninitialization + LOG(ERROR) << "Unknown input filter item_types conversion"; + item_size = sizeof(gr_complex); // avoids uninitialization + input_size_ = 0; // notify wrong configuration } const double default_if = 0.0; const double if_aux = configuration->property(role_ + ".if", default_if); @@ -95,7 +93,7 @@ PulseBlankingFilter::PulseBlankingFilter(const ConfigurationInterface* configura void PulseBlankingFilter::connect(gr::top_block_sptr top_block) { - if (input_item_type_ == "gr_complex") + if (item_type_ == "gr_complex") { if (dump_) { @@ -116,7 +114,7 @@ void PulseBlankingFilter::connect(gr::top_block_sptr top_block) void PulseBlankingFilter::disconnect(gr::top_block_sptr top_block) { - if (input_item_type_ == "gr_complex") + if (item_type_ == "gr_complex") { if (dump_) { @@ -136,7 +134,7 @@ void PulseBlankingFilter::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr PulseBlankingFilter::get_left_block() { - if (input_item_type_ == "gr_complex") + if (item_type_ == "gr_complex") { if (xlat_) { @@ -151,7 +149,7 @@ gr::basic_block_sptr PulseBlankingFilter::get_left_block() gr::basic_block_sptr PulseBlankingFilter::get_right_block() { - if (input_item_type_ == "gr_complex") + if (item_type_ == "gr_complex") { return pulse_blanking_cc_; } diff --git a/src/algorithms/input_filter/adapters/pulse_blanking_filter.h b/src/algorithms/input_filter/adapters/pulse_blanking_filter.h index bd5411a6b..6cadc209f 100644 --- a/src/algorithms/input_filter/adapters/pulse_blanking_filter.h +++ b/src/algorithms/input_filter/adapters/pulse_blanking_filter.h @@ -71,8 +71,7 @@ private: gr::filter::freq_xlating_fir_filter_ccf::sptr freq_xlating_; gr::blocks::file_sink::sptr file_sink_; std::string dump_filename_; - std::string input_item_type_; - std::string output_item_type_; + std::string item_type_; std::string role_; size_t input_size_; unsigned int in_streams_; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 967c50807..c6f684e83 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -753,12 +753,26 @@ int GNSSFlowgraph::connect_signal_conditioners() } if (std::string::npos != reported_error.find(std::string("InputFilter"))) { - help_hint_ += " * The InputFilter implementation set in the configuration file does not exist\n"; + if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) + { + help_hint_ += " * The configured InputFilter input/output item types are not well defined.\n"; + } + else + { + help_hint_ += " * The InputFilter implementation set in the configuration file does not exist\n"; + } help_hint_ += " Check the InputFilter documentation at https://gnss-sdr.org/docs/sp-blocks/input-filter/\n"; } if (std::string::npos != reported_error.find(std::string("Resampler"))) { - help_hint_ += " * The Resampler implementation set in the configuration file does not exist\n"; + if (std::string::npos != reported_error.find(std::string("itemsize mismatch"))) + { + help_hint_ += " * The configured Resampler item type is not well defined.\n"; + } + else + { + help_hint_ += " * The Resampler implementation set in the configuration file does not exist\n"; + } help_hint_ += " Check the Resampler documentation at https://gnss-sdr.org/docs/sp-blocks/resampler/\n"; } return 1;