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_;