mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-30 23:03:05 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -28,6 +28,15 @@ SPDX-FileCopyrightText: 2011-2021 Carles Fernandez-Prades <carles.fernandez@cttc | |||||||
| - Improved handling of change in GNU Radio 3.9 FFT API. | - Improved handling of change in GNU Radio 3.9 FFT API. | ||||||
| - Improved handling of the filesystem library. | - Improved handling of the filesystem library. | ||||||
| - Do not apply clang-tidy fixes to protobuf-generated headers. | - Do not apply clang-tidy fixes to protobuf-generated headers. | ||||||
|  | - Refactored private implementation of flow graph connection and disconnection | ||||||
|  |   for improved source code readability. | ||||||
|  |  | ||||||
|  | ### Improvements in Usability: | ||||||
|  |  | ||||||
|  | - Avoid segmentation faults in the flow graph connection and/or starting due to | ||||||
|  |   some common inconsistencies in the configuration file. | ||||||
|  | - Provide hints to the user in case of failed flow graph connection due to | ||||||
|  |   inconsistencies in the configuration file. | ||||||
|  |  | ||||||
|   |   | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
|  |  | ||||||
| #include "signal_conditioner.h" | #include "signal_conditioner.h" | ||||||
| #include <glog/logging.h> | #include <glog/logging.h> | ||||||
|  | #include <stdexcept> | ||||||
| #include <utility> | #include <utility> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -40,6 +41,18 @@ void SignalConditioner::connect(gr::top_block_sptr top_block) | |||||||
|             LOG(WARNING) << "Signal conditioner already connected internally"; |             LOG(WARNING) << "Signal conditioner already connected internally"; | ||||||
|             return; |             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); |     data_type_adapt_->connect(top_block); | ||||||
|     in_filt_->connect(top_block); |     in_filt_->connect(top_block); | ||||||
|     res_->connect(top_block); |     res_->connect(top_block); | ||||||
|   | |||||||
| @@ -300,7 +300,6 @@ int ControlThread::run() | |||||||
|         } |         } | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             LOG(ERROR) << "Unable to connect flowgraph"; |  | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|     // Start the flowgraph |     // Start the flowgraph | ||||||
| @@ -311,7 +310,6 @@ int ControlThread::run() | |||||||
|         } |         } | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             LOG(ERROR) << "Unable to start flowgraph"; |  | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -374,6 +374,7 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetChannel( | |||||||
|     if (acq_item_type != trk_item_type) |     if (acq_item_type != trk_item_type) | ||||||
|         { |         { | ||||||
|             LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; |             LOG(ERROR) << "Acquisition and Tracking blocks must have the same input data type!"; | ||||||
|  |             return nullptr; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     LOG(INFO) << "Instantiating Channel " << channel |     LOG(INFO) << "Instantiating Channel " << channel | ||||||
| @@ -388,6 +389,11 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetChannel( | |||||||
|     std::unique_ptr<TrackingInterface> trk_ = GetTrkBlock(configuration, "Tracking_" + signal + appendix2, 1, 1); |     std::unique_ptr<TrackingInterface> trk_ = GetTrkBlock(configuration, "Tracking_" + signal + appendix2, 1, 1); | ||||||
|     std::unique_ptr<TelemetryDecoderInterface> tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_" + signal + appendix3, 1, 1); |     std::unique_ptr<TelemetryDecoderInterface> tlm_ = GetTlmBlock(configuration, "TelemetryDecoder_" + signal + appendix3, 1, 1); | ||||||
|  |  | ||||||
|  |     if (acq_ == nullptr or trk_ == nullptr or tlm_ == nullptr) | ||||||
|  |         { | ||||||
|  |             return nullptr; | ||||||
|  |         } | ||||||
|  |  | ||||||
|     std::unique_ptr<GNSSBlockInterface> channel_ = std::make_unique<Channel>(configuration, channel, |     std::unique_ptr<GNSSBlockInterface> channel_ = std::make_unique<Channel>(configuration, channel, | ||||||
|         std::move(acq_), |         std::move(acq_), | ||||||
|         std::move(trk_), |         std::move(trk_), | ||||||
| @@ -1320,8 +1326,7 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock( | |||||||
|  |  | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             // Log fatal. This causes execution to stop. |             LOG(ERROR) << role << " block: Undefined implementation " << implementation; | ||||||
|             LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; |  | ||||||
|         } |         } | ||||||
|     return block; |     return block; | ||||||
| } | } | ||||||
| @@ -1515,8 +1520,7 @@ std::unique_ptr<AcquisitionInterface> GNSSBlockFactory::GetAcqBlock( | |||||||
|  |  | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             // Log fatal. This causes execution to stop. |             LOG(ERROR) << role << " block: Undefined implementation " << implementation; | ||||||
|             LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; |  | ||||||
|         } |         } | ||||||
|     return block; |     return block; | ||||||
| } | } | ||||||
| @@ -1671,8 +1675,7 @@ std::unique_ptr<TrackingInterface> GNSSBlockFactory::GetTrkBlock( | |||||||
| #endif | #endif | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             // Log fatal. This causes execution to stop. |             LOG(ERROR) << role << " block: Undefined implementation " << implementation; | ||||||
|             LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; |  | ||||||
|         } |         } | ||||||
|     return block; |     return block; | ||||||
| } | } | ||||||
| @@ -1764,8 +1767,7 @@ std::unique_ptr<TelemetryDecoderInterface> GNSSBlockFactory::GetTlmBlock( | |||||||
|  |  | ||||||
|     else |     else | ||||||
|         { |         { | ||||||
|             // Log fatal. This causes execution to stop. |             LOG(ERROR) << role << " block: Undefined implementation " << implementation; | ||||||
|             LOG(ERROR) << role << "." << implementation << ": Undefined implementation for block"; |  | ||||||
|         } |         } | ||||||
|     return block; |     return block; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -128,7 +128,10 @@ void GNSSFlowgraph::init() | |||||||
|             // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. |             // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. | ||||||
|             // Include GetRFChannels in the interface to avoid read config parameters here |             // Include GetRFChannels in the interface to avoid read config parameters here | ||||||
|             // read the number of RF channels for each front-end |             // 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) |             if (RF_Channels != 0) | ||||||
|                 { |                 { | ||||||
|                     for (int j = 0; j < RF_Channels; j++) |                     for (int j = 0; j < RF_Channels; j++) | ||||||
| @@ -265,6 +268,7 @@ void GNSSFlowgraph::start() | |||||||
|     catch (const std::exception& e) |     catch (const std::exception& e) | ||||||
|         { |         { | ||||||
|             LOG(ERROR) << "Unable to start flowgraph: " << e.what(); |             LOG(ERROR) << "Unable to start flowgraph: " << e.what(); | ||||||
|  |             print_help(); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -321,11 +325,15 @@ void GNSSFlowgraph::connect() | |||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|     if (connect_fpga_flowgraph() != 0) |     if (connect_fpga_flowgraph() != 0) | ||||||
|         { |         { | ||||||
|  |             LOG(ERROR) << "Unable to connect flowgraph with FPFA off-loading"; | ||||||
|  |             print_help(); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| #else | #else | ||||||
|     if (connect_desktop_flowgraph() != 0) |     if (connect_desktop_flowgraph() != 0) | ||||||
|         { |         { | ||||||
|  |             LOG(ERROR) << "Unable to connect flowgraph"; | ||||||
|  |             print_help(); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| #endif | #endif | ||||||
| @@ -342,7 +350,7 @@ void GNSSFlowgraph::disconnect() | |||||||
|  |  | ||||||
|     if (!connected_) |     if (!connected_) | ||||||
|         { |         { | ||||||
|             LOG(INFO) << "flowgraph was not connected"; |             LOG(INFO) << "Flowgraph was not connected"; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     connected_ = false; |     connected_ = false; | ||||||
| @@ -539,19 +547,28 @@ int GNSSFlowgraph::connect_fpga_flowgraph() | |||||||
|     DLOG(INFO) << "Blocks connected internally to the top_block"; |     DLOG(INFO) << "Blocks connected internally to the top_block"; | ||||||
|  |  | ||||||
|     // Connect the counter |     // 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 |     else | ||||||
|         { |         { | ||||||
|             if (connect_fpga_sample_counter() != 0) |             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; |             return 1; | ||||||
|                 } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     if (connect_channels_to_observables() != 0) |     if (connect_channels_to_observables() != 0) | ||||||
| @@ -575,6 +592,9 @@ int GNSSFlowgraph::connect_fpga_flowgraph() | |||||||
|         { |         { | ||||||
|             return 1; |             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"; |     LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration with FPGA off-loading has been successfully connected"; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @@ -654,13 +674,23 @@ int GNSSFlowgraph::connect_signal_sources() | |||||||
| { | { | ||||||
|     for (int i = 0; i < sources_count_; i++) |     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(); |                     top_block_->disconnect_all(); | ||||||
|                     return 1; |                     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() | int GNSSFlowgraph::connect_channels() | ||||||
| { | { | ||||||
|     for (int i = 0; i < channels_count_; i++) |     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(); |                     top_block_->disconnect_all(); | ||||||
|                     return 1; |                     return 1; | ||||||
|                 } |                 } | ||||||
| @@ -730,6 +838,13 @@ int GNSSFlowgraph::disconnect_channels() | |||||||
|  |  | ||||||
| int GNSSFlowgraph::connect_observables() | 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 |     try | ||||||
|         { |         { | ||||||
|             observables_->connect(top_block_); |             observables_->connect(top_block_); | ||||||
| @@ -763,6 +878,13 @@ int GNSSFlowgraph::disconnect_observables() | |||||||
|  |  | ||||||
| int GNSSFlowgraph::connect_pvt() | 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 |     try | ||||||
|         { |         { | ||||||
|             pvt_->connect(top_block_); |             pvt_->connect(top_block_); | ||||||
| @@ -840,6 +962,7 @@ int GNSSFlowgraph::disconnect_sample_counter() | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
| int GNSSFlowgraph::connect_fpga_sample_counter() | 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! |                                     // 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_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(); |                                     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) |                                     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++; |                                     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) |             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(); |                     top_block_->disconnect_all(); | ||||||
|                     return 1; |                     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() | int GNSSFlowgraph::connect_signal_conditioners_to_channels() | ||||||
| { | { | ||||||
|     for (int i = 0; i < channels_count_; i++) |     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 |             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; |     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() | void GNSSFlowgraph::check_signal_conditioners() | ||||||
| { | { | ||||||
|     // check for unconnected signal conditioners and connect null_sinks |     // 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) | bool GNSSFlowgraph::send_telemetry_msg(const pmt::pmt_t& msg) | ||||||
| { | { | ||||||
|     // Push ephemeris to PVT telemetry msg in port using a channel out port |     // Push ephemeris to PVT telemetry msg in port using a channel out port | ||||||
|   | |||||||
| @@ -216,6 +216,8 @@ private: | |||||||
|  |  | ||||||
|     void push_back_signal(const Gnss_Signal& gs); |     void push_back_signal(const Gnss_Signal& gs); | ||||||
|     void remove_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); |     double project_doppler(const std::string& searched_signal, double primary_freq_doppler_hz); | ||||||
|     bool is_multiband() const; |     bool is_multiband() const; | ||||||
| @@ -279,6 +281,7 @@ private: | |||||||
|     std::map<std::string, StringValue> mapStringValues_; |     std::map<std::string, StringValue> mapStringValues_; | ||||||
|  |  | ||||||
|     std::string config_file_; |     std::string config_file_; | ||||||
|  |     std::string help_hint_; | ||||||
|  |  | ||||||
|     std::mutex signal_list_mutex_; |     std::mutex signal_list_mutex_; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez