From 84ae396ba06e3ccb849a9824afc7b8d2475bb83a Mon Sep 17 00:00:00 2001 From: Marc Majoral Date: Fri, 2 Oct 2026 10:16:31 +0200 Subject: [PATCH] Refactor FPGA signal sources and improve error handling --- .../adrv9361_z7035_signal_source_fpga.cc | 92 ++++--- .../adrv9361_z7035_signal_source_fpga.h | 24 +- .../adapters/dma_signal_source_fpga.cc | 249 +++++++++--------- .../adapters/dma_signal_source_fpga.h | 24 +- .../adapters/fmcomms5_signal_source_fpga.cc | 87 +++--- .../adapters/fmcomms5_signal_source_fpga.h | 22 +- .../signal_source/libs/fpga_dma-proxy.cc | 116 +++++--- .../signal_source/libs/fpga_dma-proxy.h | 22 +- .../libs/fpga_dynamic_bit_selection.cc | 106 +++++--- .../libs/fpga_dynamic_bit_selection.h | 55 ++-- 10 files changed, 458 insertions(+), 339 deletions(-) diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc index 1a39725ea..49ee18b02 100644 --- a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc @@ -16,7 +16,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -48,19 +48,19 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration const std::string &role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue *queue __attribute__((unused))) : SignalSourceBase(configuration, role, "ADRV9361_Z7035_Signal_Source_FPGA"s), - gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), - gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), - rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", DEFAULT_GAIN_MODE)), + gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", DEFAULT_GAIN_MODE)), + rf_port_select_(configuration->property(role + ".rf_port_select", DEFAULT_RF_PORT_SELECT)), filter_source_(configuration->property(role + ".filter_source", std::string("Off"))), filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), - rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), - rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), + rf_gain_rx1_(configuration->property(role + ".gain_rx1", DEFAULT_MANUAL_GAIN_RX1)), + rf_gain_rx2_(configuration->property(role + ".gain_rx2", DEFAULT_MANUAL_GAIN_RX2)), scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), - tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), + tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", DEFAULT_TX_ATTENUATION_dB)), freq0_(configuration->property(role + ".freq", GPS_L5_FREQ_HZ)), - sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), - bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), + sample_rate_(configuration->property(role + ".sampling_frequency", DEFAULT_BANDWIDTH)), + bandwidth_(configuration->property(role + ".bandwidth", DEFAULT_BANDWIDTH)), freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))), tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast(500000))), @@ -84,33 +84,27 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) #endif { - const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || - (configuration->property("Channels_1B.count", 0) > 0)); - const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || - (configuration->property("Channels_L5.count", 0) > 0) || - (configuration->property("Channels_5X.count", 0) > 0)); + CHECK(rx1_enable_ || rx2_enable_) << "At least one RX channel must be enabled."; + CHECK(sample_rate_ > 0) << "Sampling frequency must be positive."; - const uint32_t num_freq_bands = ((enable_rx1_band == true) && (enable_rx2_band == true)) ? 2 : 1; + std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; + + const uint32_t num_freq_bands = (rx1_enable_ && rx2_enable_) ? 2 : 1; if (freq0_ == 0) { // use ".freq0" freq0_ = configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ)); } - switch_fpga = std::make_shared(); - switch_fpga->set_switch_position(switch_to_real_time_mode); - - std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; - // some basic checks if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) { std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; - rf_port_select_ = default_rf_port_select; - LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; + std::cout << " This parameter has been set to its default value rf_port_select=" << DEFAULT_RF_PORT_SELECT << '\n'; + rf_port_select_ = DEFAULT_RF_PORT_SELECT; + LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << DEFAULT_RF_PORT_SELECT; } if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) @@ -118,9 +112,9 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; std::cout << " manual, slow_attack, fast_attack, hybrid\n"; std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; - gain_mode_rx1_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; + std::cout << " This parameter has been set to its default value gain_mode_rx1=" << DEFAULT_GAIN_MODE << '\n'; + gain_mode_rx1_ = DEFAULT_GAIN_MODE; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << DEFAULT_GAIN_MODE; } if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) @@ -128,9 +122,9 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; std::cout << " manual, slow_attack, fast_attack, hybrid\n"; std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; - gain_mode_rx2_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; + std::cout << " This parameter has been set to its default value gain_mode_rx2=" << DEFAULT_GAIN_MODE << '\n'; + gain_mode_rx2_ = DEFAULT_GAIN_MODE; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << DEFAULT_GAIN_MODE; } if (gain_mode_rx1_ == "manual") @@ -139,9 +133,9 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration { std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; - rf_gain_rx1_ = default_manual_gain_rx1; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; + std::cout << " This parameter has been set to its default value rf_gain_rx1=" << DEFAULT_MANUAL_GAIN_RX1 << '\n'; + rf_gain_rx1_ = DEFAULT_MANUAL_GAIN_RX1; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << DEFAULT_MANUAL_GAIN_RX1; } } @@ -151,9 +145,9 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration { std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; - rf_gain_rx2_ = default_manual_gain_rx2; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; + std::cout << " This parameter has been set to its default value rf_gain_rx2=" << DEFAULT_MANUAL_GAIN_RX2 << '\n'; + rf_gain_rx2_ = DEFAULT_MANUAL_GAIN_RX2; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << DEFAULT_MANUAL_GAIN_RX2; } } @@ -174,13 +168,16 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration { std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; - bandwidth_ = default_bandwidth; - LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; + std::cout << " This parameter has been set to its default value bandwidth=" << DEFAULT_BANDWIDTH << '\n'; + bandwidth_ = DEFAULT_BANDWIDTH; + LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << DEFAULT_BANDWIDTH; } std::cout << "LO frequency : " << freq0_ << " Hz\n"; + switch_fpga = std::make_shared(); + switch_fpga->set_switch_position(REAL_TIME_MODE); + uint64_t freq1 = 0; // The local oscillator frequency of the ADRV9361-B is not used when using the ADRV9361-Z7035 board. try @@ -224,9 +221,9 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration { std::cout << "Configuration parameter tx_attenuation_db should take values between 0.0 and -89.95 in 0.25 dB steps\n"; std::cout << "Error: provided value tx_attenuation_db=" << tx_attenuation_db_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value tx_attenuation_db=" << default_tx_attenuation_db << '\n'; - tx_attenuation_db_ = default_tx_attenuation_db; - LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << default_tx_attenuation_db; + std::cout << " This parameter has been set to its default value tx_attenuation_db=" << DEFAULT_TX_ATTENUATION_dB << '\n'; + tx_attenuation_db_ = DEFAULT_TX_ATTENUATION_dB; + LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << DEFAULT_TX_ATTENUATION_dB; } try { @@ -245,7 +242,7 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration } } - std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + std::string dump_filename = configuration->property(role + ".dump_filename", DEFAULT_DUMP_FILENAME); buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); @@ -253,7 +250,7 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration // dynamic bits selection if (enable_dynamic_bit_selection_) { - dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + dynamic_bit_selection_fpga = std::make_shared(rx1_enable_, rx2_enable_); thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); } @@ -339,7 +336,7 @@ void Adrv9361z7035SignalSourceFPGA::run_dynamic_bit_selection_process() { // setting the bit selection to the top bits dynamic_bit_selection_fpga->bit_selection(); - std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(GAIN_CONTROL_PERIOD_ms)); std::lock_guard lock(dynamic_bit_selection_mutex); if (enable_dynamic_bit_selection_ == false) { @@ -353,7 +350,7 @@ void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process() { bool enable_ovf_check_buffer_monitor_active = true; - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(BUFFER_MONITOR_INITIAL_DELAY_ms)); while (enable_ovf_check_buffer_monitor_active) { @@ -362,10 +359,9 @@ void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process() // If a buffer overflow is detected, the receiver may not function correctly. // This compromises system reliability and can lead to undefined behavior. // To prevent further issues, execution is halted. - LOG(ERROR) << "Buffer Overflow Detected – Execution Halted"; - exit(1); + LOG(FATAL) << "Buffer Overflow Detected – Execution Halted"; } - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(BUFFER_MONITOR_PERIOD_ms)); std::lock_guard lock(buffer_monitor_mutex); if (enable_ovf_check_buffer_monitor_active_ == false) { diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h index 286cde2d5..a12f26a60 100644 --- a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h @@ -12,7 +12,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -63,21 +63,21 @@ public: gr::basic_block_sptr get_right_block() override; private: - const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); - const std::string default_rf_port_select = std::string("A_BALANCED"); - const std::string default_gain_mode = std::string("slow_attack"); - const double default_tx_attenuation_db = -10.0; - const double default_manual_gain_rx1 = 64.0; - const double default_manual_gain_rx2 = 64.0; - const uint64_t default_bandwidth = 12500000; + const std::string DEFAULT_DUMP_FILENAME = std::string("FPGA_buffer_monitor_dump.dat"); + const std::string DEFAULT_RF_PORT_SELECT = std::string("A_BALANCED"); + const std::string DEFAULT_GAIN_MODE = std::string("slow_attack"); + const double DEFAULT_TX_ATTENUATION_dB = -10.0; + const double DEFAULT_MANUAL_GAIN_RX1 = 64.0; + const double DEFAULT_MANUAL_GAIN_RX2 = 64.0; + const uint64_t DEFAULT_BANDWIDTH = 12500000; // perform dynamic bit selection every 500 ms by default - const uint32_t Gain_control_period_ms = 500; + const uint32_t GAIN_CONTROL_PERIOD_ms = 500; // check buffer overflow and perform buffer monitoring every 1s by default - const uint32_t buffer_monitor_period_ms = 1000; + const uint32_t BUFFER_MONITOR_PERIOD_ms = 1000; // buffer overflow and buffer monitoring initial delay - const uint32_t buffer_monitoring_initial_delay_ms = 2000; - const int32_t switch_to_real_time_mode = 2; + const uint32_t BUFFER_MONITOR_INITIAL_DELAY_ms = 2000; + const int32_t REAL_TIME_MODE = 2; void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc index 6d4f91b03..155c39cf4 100644 --- a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc @@ -10,7 +10,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -23,10 +23,12 @@ #include "gnss_sdr_string_literals.h" #include // for std::min #include // for std::chrono +#include // for std::isfinite #include // for open, O_WRONLY #include // for std::ifstream #include // for std::setprecision #include // for std::cout +#include // for std::numeric_limits #include // fr std::vector #if USE_GLOG_AND_GFLAGS @@ -43,9 +45,9 @@ DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configura Concurrent_Queue *queue __attribute__((unused))) : SignalSourceBase(configuration, role, "DMA_Signal_Source_FPGA"s), queue_(queue), - filename0_(configuration->property(role + ".filename", empty_string)), - sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), - samples_to_skip_(0), + filename0_(configuration->property(role + ".filename", EMPTY_STRING)), + sample_rate_(configuration->property(role + ".sampling_frequency", DEFAULT_BANDWIDTH)), + bytes_to_skip_(0), samples_(configuration->property(role + ".samples", static_cast(0))), num_input_files_(1), dma_buff_offset_pos_(0), @@ -53,18 +55,14 @@ DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configura out_stream_(out_stream), item_size_(sizeof(int8_t)), enable_DMA_(false), + rx1_enable_(configuration->property(role + ".rx1_enable", true)), + rx2_enable_(configuration->property(role + ".rx2_enable", true)), enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), repeat_(configuration->property(role + ".repeat", false)) { const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", 0.0); const size_t header_size = configuration->property(role + ".header_size", 0); - const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || - (configuration->property("Channels_1B.count", 0) > 0)); - const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || - (configuration->property("Channels_L5.count", 0) > 0) || - (configuration->property("Channels_5X.count", 0) > 0)); - #if USE_GLOG_AND_GFLAGS // override value with commandline flag, if present if (FLAGS_signal_source != "-") @@ -85,102 +83,98 @@ DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configura filename0_ = absl::GetFlag(FLAGS_s); } #endif + if (filename0_.empty()) { - num_input_files_ = 2; - filename0_ = configuration->property(role + ".filename0", empty_string); - filename1_ = configuration->property(role + ".filename1", empty_string); - } - // if only one input file is specified in the configuration file then: - // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels - // otherwise the DMA transfers the samples to the L2/L5 frequency band channels - // if more than one input file are specified then the DMA transfer the samples to both the L1 and the L2/L5 frequency channels. - if (filename1_.empty()) - { - if (enable_rx1_band) - { - dma_buff_offset_pos_ = 2; - } - } - else - { - dma_buff_offset_pos_ = 2; + filename0_ = configuration->property(role + ".filename0", EMPTY_STRING); } - if (seconds_to_skip > 0) + filename1_ = configuration->property(role + ".filename1", EMPTY_STRING); + + if ((!configuration->is_present(role + ".rx1_enable")) && (!configuration->is_present(role + ".rx2_enable"))) { - samples_to_skip_ = static_cast(seconds_to_skip * sample_rate_) * 2; + // If neither RX enable flag is specified, enable each RX with a nonempty input filename. + rx1_enable_ = !filename0_.empty(); + rx2_enable_ = !filename1_.empty(); } - if (header_size > 0) + + // configuration file check + const bool only_filename0_provided = !filename0_.empty() && filename1_.empty(); + const bool both_filenames_provided = !filename0_.empty() && !filename1_.empty(); + const bool one_freq_band_enabled = rx1_enable_ != rx2_enable_; + const bool both_freq_bands_enabled = rx1_enable_ && rx2_enable_; + + if (!((only_filename0_provided && one_freq_band_enabled) || + (both_filenames_provided && both_freq_bands_enabled))) { - samples_to_skip_ += header_size; + LOG(FATAL) << "Configuration error: one input file requires exactly one enabled " + "frequency band; two input files require both frequency bands enabled."; } + num_input_files_ = filename1_.empty() ? 1U : 2U; + + // Set the DMA buffer offset. + if (rx1_enable_) + { + dma_buff_offset_pos_ = IQ_COMPONENTS_PER_SAMPLE; + } + + + CHECK(sample_rate_ > 0) << "Sampling frequency must be positive."; + CHECK(std::isfinite(seconds_to_skip) && seconds_to_skip >= 0) + << "Seconds to skip must be finite and nonnegative."; + CHECK(samples_ >= 0) << "Sample count must be nonnegative."; + + const uint64_t bytes_per_sample = IQ_COMPONENTS_PER_SAMPLE * item_size_; + const long double samples_to_skip = + static_cast(seconds_to_skip) * sample_rate_; + // Leave room for the header and keep ignore()'s byte count representable. + CHECK(static_cast(header_size) < + static_cast(std::numeric_limits::max())) + << "Header size is too large."; + CHECK(samples_to_skip < + (static_cast(std::numeric_limits::max()) - + header_size) / + bytes_per_sample) + << "Requested skip is too large."; + bytes_to_skip_ = static_cast(samples_to_skip) * bytes_per_sample + + header_size; + switch_fpga = std::make_shared(); - switch_fpga->set_switch_position(switch_to_DMA); + switch_fpga->set_switch_position(POST_PROCESSING_MODE); enable_DMA_ = true; - if (samples_ == 0) // read all file + // Validate both files before starting the DMA thread. + uint64_t available = get_available_items(filename0_); + if (num_input_files_ == 2) { - std::ifstream file(filename0_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - std::ifstream::pos_type size; - - if (file.is_open()) - { - size = file.tellg(); - DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); - } - else - { - std::cerr << "SignalSource: Unable to open the samples file " << filename0_.c_str() << '\n'; - return; - } - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(16); - std::cout << "Processing file " << filename0_ << ", which contains " << static_cast(size) << " [bytes]\n"; - std::cout.precision(ss); - - if (size > 0) - { - const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; - const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; - samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms - } - - if (!filename1_.empty()) - { - std::ifstream file(filename1_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - std::ifstream::pos_type size; - - if (file.is_open()) - { - size = file.tellg(); - DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); - } - else - { - std::cerr << "SignalSource: Unable to open the samples file " << filename1_.c_str() << '\n'; - return; - } - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(16); - std::cout << "Processing file " << filename1_ << ", which contains " << static_cast(size) << " [bytes]\n"; - std::cout.precision(ss); - - int64_t samples_rx2 = 0; - if (size > 0) - { - const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; - const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; - samples_rx2 = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms - } - samples_ = std::min(samples_, samples_rx2); - } + available = std::min(available, get_available_items(filename1_)); } + if (samples_ == 0) + { + // Preserve the existing tail margin: about 1 ms of interleaved I/Q. + const uint64_t tail_items = sample_rate_ / 500 + + (sample_rate_ % 500 != 0 ? 1 : 0); + CHECK(available > tail_items) + << "File does not contain enough samples to process."; + uint64_t items_to_process = available - tail_items; + items_to_process -= items_to_process % IQ_COMPONENTS_PER_SAMPLE; + CHECK(items_to_process <= + static_cast(std::numeric_limits::max())) + << "Input sample count is too large."; + samples_ = static_cast(items_to_process); + } + else + { + CHECK(static_cast(samples_) <= available) + << "Requested sample count exceeds the available input data."; + } + + CHECK(samples_ % IQ_COMPONENTS_PER_SAMPLE == 0) << "Sample count must contain complete I/Q pairs."; CHECK(samples_ > 0) << "File does not contain enough samples to process."; - double signal_duration_s = (static_cast(samples_) * (1 / static_cast(sample_rate_))) / 2.0; + double signal_duration_s = (static_cast(samples_) * (1 / static_cast(sample_rate_))) / static_cast(IQ_COMPONENTS_PER_SAMPLE); DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; @@ -199,12 +193,11 @@ DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configura DLOG(INFO) << "Item type " << std::string("ibyte"); DLOG(INFO) << "Item size " << item_size_; DLOG(INFO) << "Repeat " << repeat_; - // } // dynamic bits selection if (enable_dynamic_bit_selection_) { - dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + dynamic_bit_selection_fpga = std::make_shared(rx1_enable_, rx2_enable_); thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); } @@ -246,19 +239,39 @@ DMASignalSourceFPGA::~DMASignalSourceFPGA() } } +uint64_t DMASignalSourceFPGA::get_available_items( + const std::string &filename) const +{ + std::ifstream file(filename, std::ios::binary | std::ios::ate); + CHECK(file.is_open()) << "Cannot open input file: " << filename; + + const auto position = file.tellg(); + CHECK(position != std::ifstream::pos_type(-1)) + << "Cannot determine input file size: " << filename; + + const uint64_t file_size = static_cast(position); + CHECK(bytes_to_skip_ <= file_size) + << "Requested skip of " << bytes_to_skip_ + << " bytes exceeds file size of " << file_size + << " bytes: " << filename; + + std::cout << "Processing file " << filename + << ", which contains " << file_size << " [bytes]\n"; + + return (file_size - bytes_to_skip_) / item_size_; +} void DMASignalSourceFPGA::start() { - thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); + thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, bytes_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); } -void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue *queue) +void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &bytes_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue *queue) { std::ifstream infile1; infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); - // FPGA DMA control dma_fpga = std::make_shared(); @@ -293,10 +306,9 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s } // skip the initial samples if needed - uint64_t bytes_to_skeep = samples_to_skip * item_size; try { - infile1.ignore(bytes_to_skeep); + infile1.ignore(bytes_to_skip); } catch (const std::ifstream::failure &e) { @@ -310,7 +322,7 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s { try { - infile2.ignore(bytes_to_skeep); + infile2.ignore(bytes_to_skip); } catch (const std::ifstream::failure &e) { @@ -321,10 +333,8 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s } } - // rx signal vectors - std::vector input_samples(sample_block_size * 2); // complex samples - // pointer to DMA buffer int8_t *dma_buffer; + uint32_t dma_buffer_size; int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1 bool run_DMA = true; @@ -337,22 +347,26 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s return; } dma_buffer = dma_fpga->get_buffer_address(); + dma_buffer_size = dma_fpga->get_buffer_size(); + uint32_t sample_block_size = dma_buffer_size / IQ_COMPONENTS_PER_DMA_FRAME; - // if only one frequency band is used then clear the samples corresponding to the unused frequency band + std::vector input_samples(sample_block_size * IQ_COMPONENTS_PER_SAMPLE); uint32_t dma_index = 0; + + // Clear every unused-band I/Q pair in the reusable DMA buffer. if (num_input_files_ == 1) { - // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. - for (int index0 = 0; index0 < (nread_elements); index0 += 2) + for (uint32_t sample = 0; sample < sample_block_size; ++sample) { - dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; - dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; - dma_index += 4; + const uint32_t unused_pos = + sample * IQ_COMPONENTS_PER_DMA_FRAME + (IQ_COMPONENTS_PER_SAMPLE - dma_buff_offset_pos); + dma_buffer[unused_pos] = 0; + dma_buffer[unused_pos + 1] = 0; } } uint64_t nbytes_remaining = samples * item_size; - uint32_t read_buffer_size = sample_block_size * 2; // complex samples + uint32_t read_buffer_size = sample_block_size * IQ_COMPONENTS_PER_SAMPLE; // complex samples // run the DMA while (run_DMA) @@ -384,12 +398,11 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s nread_elements = infile1.gcount(); } - for (int index0 = 0; index0 < (nread_elements); index0 += 2) + for (int index0 = 0; index0 < (nread_elements); index0 += IQ_COMPONENTS_PER_SAMPLE) { - // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands dma_buffer[dma_index + dma_buff_offset_pos] = input_samples[index0]; dma_buffer[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; - dma_index += 4; + dma_index += IQ_COMPONENTS_PER_DMA_FRAME; } // read filename 1 (if enabled) @@ -415,18 +428,17 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s nread_elements = infile2.gcount(); } - for (int index0 = 0; index0 < (nread_elements); index0 += 2) + for (int index0 = 0; index0 < (nread_elements); index0 += IQ_COMPONENTS_PER_SAMPLE) { - // filename2 is never the L1 band dma_buffer[dma_index] = input_samples[index0]; dma_buffer[dma_index + 1] = input_samples[index0 + 1]; - dma_index += 4; + dma_index += IQ_COMPONENTS_PER_DMA_FRAME; } } if (nread_elements > 0) { - if (dma_fpga->DMA_write(nread_elements * 2)) + if (dma_fpga->DMA_write((nread_elements / IQ_COMPONENTS_PER_SAMPLE) * IQ_COMPONENTS_PER_DMA_FRAME)) { std::cerr << "Error: DMA could not send all the required samples\n"; break; @@ -441,7 +453,7 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s { // read the file again nbytes_remaining = samples * item_size; - read_buffer_size = sample_block_size * 2; + read_buffer_size = sample_block_size * IQ_COMPONENTS_PER_SAMPLE; try { infile1.seekg(0); @@ -453,10 +465,9 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s } // skip the initial samples if needed - uint64_t bytes_to_skeep = samples_to_skip * item_size; try { - infile1.ignore(bytes_to_skeep); + infile1.ignore(bytes_to_skip); } catch (const std::ifstream::failure &e) { @@ -478,7 +489,7 @@ void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const s try { - infile2.ignore(bytes_to_skeep); + infile2.ignore(bytes_to_skip); } catch (const std::ifstream::failure &e) { @@ -539,7 +550,7 @@ void DMASignalSourceFPGA::run_dynamic_bit_selection_process() { // setting the bit selection to the top bits dynamic_bit_selection_fpga->bit_selection(); - std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(GAIN_CONTROL_PERIOD_ms)); std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); if (enable_dynamic_bit_selection_ == false) { diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h index efbad3b23..7d0a2e9d1 100644 --- a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h @@ -10,7 +10,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -63,18 +63,18 @@ public: gr::basic_block_sptr get_right_block() override; private: - const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name - const std::string empty_string; - const uint64_t default_bandwidth = 12500000; - // perform dynamic bit selection every 500 ms by default - const uint32_t Gain_control_period_ms = 500; - // sample block size when running in post-processing mode - const int sample_block_size = 16384; - const int32_t switch_to_DMA = 0; + const std::string EMPTY_STRING; + const uint64_t DEFAULT_BANDWIDTH = 12500000; + const uint32_t GAIN_CONTROL_PERIOD_ms = 500; // perform dynamic bit selection every 500 ms by default + const int32_t POST_PROCESSING_MODE = 0; + const uint32_t IQ_COMPONENTS_PER_SAMPLE = 2; + static constexpr uint32_t IQ_COMPONENTS_PER_DMA_FRAME = 4; // Two signals, each with I and Q. + + uint64_t get_available_items(const std::string &filename) const; void run_DMA_process(const std::string &filename0, const std::string &filename1, - uint64_t &samples_to_skip, + uint64_t &bytes_to_skip, size_t &item_size, int64_t &samples, bool &repeat, @@ -99,7 +99,7 @@ private: std::string filename1_; uint64_t sample_rate_; - uint64_t samples_to_skip_; + uint64_t bytes_to_skip_; int64_t samples_; uint32_t num_input_files_; uint32_t dma_buff_offset_pos_; @@ -108,6 +108,8 @@ private: size_t item_size_; bool enable_DMA_; + bool rx1_enable_; + bool rx2_enable_; bool enable_dynamic_bit_selection_; bool repeat_; }; diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc index bffe11db5..c54915cc4 100644 --- a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc @@ -16,7 +16,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -48,17 +48,17 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface const std::string &role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue *queue __attribute__((unused))) : SignalSourceBase(configuration, role, "FMCOMMS5_Signal_Source_FPGA"s), - gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), - gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), - rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", DEFAULT_GAIN_MODE)), + gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", DEFAULT_GAIN_MODE)), + rf_port_select_(configuration->property(role + ".rf_port_select", DEFAULT_RF_PORT_SELECT)), filter_source_(configuration->property(role + ".filter_source", std::string("Off"))), filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), - rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), - rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), + rf_gain_rx1_(configuration->property(role + ".gain_rx1", DEFAULT_MANUAL_GAIN_RX1)), + rf_gain_rx2_(configuration->property(role + ".gain_rx2", DEFAULT_MANUAL_GAIN_RX2)), freq0_(configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ))), freq1_(configuration->property(role + ".freq1", static_cast(GPS_L5_FREQ_HZ))), - sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), - bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), + sample_rate_(configuration->property(role + ".sampling_frequency", DEFAULT_BANDWIDTH)), + bandwidth_(configuration->property(role + ".bandwidth", DEFAULT_BANDWIDTH)), Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))), Fstop_(configuration->property(role + ".Fstop", static_cast(0.0))), in_stream_(in_stream), @@ -78,16 +78,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) #endif { - const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || - (configuration->property("Channels_1B.count", 0) > 0)); - const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || - (configuration->property("Channels_L5.count", 0) > 0) || - (configuration->property("Channels_5X.count", 0) > 0)); - - const uint32_t num_freq_bands = ((enable_rx1_band == true) && (enable_rx2_band == true)) ? 2 : 1; - - switch_fpga = std::make_shared(); - switch_fpga->set_switch_position(switch_to_real_time_mode); + CHECK(rx1_enable_ || rx2_enable_) << "At least one RX channel must be enabled."; + CHECK(sample_rate_ > 0) << "Sampling frequency must be positive."; + const uint32_t num_freq_bands = (rx1_enable_ && rx2_enable_) ? 2U : 1U; std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; @@ -97,9 +90,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; - rf_port_select_ = default_rf_port_select; - LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; + std::cout << " This parameter has been set to its default value rf_port_select=" << DEFAULT_RF_PORT_SELECT << '\n'; + rf_port_select_ = DEFAULT_RF_PORT_SELECT; + LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << DEFAULT_RF_PORT_SELECT; } if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) @@ -107,9 +100,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; std::cout << " manual, slow_attack, fast_attack, hybrid\n"; std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; - gain_mode_rx1_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; + std::cout << " This parameter has been set to its default value gain_mode_rx1=" << DEFAULT_GAIN_MODE << '\n'; + gain_mode_rx1_ = DEFAULT_GAIN_MODE; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << DEFAULT_GAIN_MODE; } if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) @@ -117,9 +110,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; std::cout << " manual, slow_attack, fast_attack, hybrid\n"; std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; - gain_mode_rx2_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; + std::cout << " This parameter has been set to its default value gain_mode_rx2=" << DEFAULT_GAIN_MODE << '\n'; + gain_mode_rx2_ = DEFAULT_GAIN_MODE; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << DEFAULT_GAIN_MODE; } if (gain_mode_rx1_ == "manual") @@ -128,9 +121,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface { std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; - rf_gain_rx1_ = default_manual_gain_rx1; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; + std::cout << " This parameter has been set to its default value rf_gain_rx1=" << DEFAULT_MANUAL_GAIN_RX1 << '\n'; + rf_gain_rx1_ = DEFAULT_MANUAL_GAIN_RX1; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << DEFAULT_MANUAL_GAIN_RX1; } } @@ -140,9 +133,9 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface { std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; - rf_gain_rx2_ = default_manual_gain_rx2; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; + std::cout << " This parameter has been set to its default value rf_gain_rx2=" << DEFAULT_MANUAL_GAIN_RX2 << '\n'; + rf_gain_rx2_ = DEFAULT_MANUAL_GAIN_RX2; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << DEFAULT_MANUAL_GAIN_RX2; } } @@ -163,19 +156,24 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface { std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; - bandwidth_ = default_bandwidth; - LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; + std::cout << " This parameter has been set to its default value bandwidth=" << DEFAULT_BANDWIDTH << '\n'; + bandwidth_ = DEFAULT_BANDWIDTH; + LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << DEFAULT_BANDWIDTH; } - if (enable_rx1_band) + if (rx1_enable_) { std::cout << "LO 0 frequency : " << freq0_ << " Hz\n"; } - if (enable_rx2_band) + if (rx2_enable_) { std::cout << "LO 1 frequency : " << freq1_ << " Hz\n"; } + + + switch_fpga = std::make_shared(); + switch_fpga->set_switch_position(REAL_TIME_MODE); + try { config_ad9361_rx_local(bandwidth_, @@ -203,7 +201,7 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface return; } - std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + std::string dump_filename = configuration->property(role + ".dump_filename", DEFAULT_NUM_FILENAME); buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); @@ -211,7 +209,7 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface // dynamic bits selection if (enable_dynamic_bit_selection_) { - dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + dynamic_bit_selection_fpga = std::make_shared(rx1_enable_, rx2_enable_); thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); } @@ -284,7 +282,7 @@ void Fmcomms5SignalSourceFPGA::run_dynamic_bit_selection_process() { // setting the bit selection to the top bits dynamic_bit_selection_fpga->bit_selection(); - std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(GAIN_CONTROL_PERIOD_ms)); std::lock_guard lock(dynamic_bit_selection_mutex); if (enable_dynamic_bit_selection_ == false) { @@ -298,7 +296,7 @@ void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process() { bool enable_ovf_check_buffer_monitor_active = true; - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(BUFFER_MONITOR_INITIAL_DELAY_ms)); while (enable_ovf_check_buffer_monitor_active) { @@ -307,10 +305,9 @@ void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process() // If a buffer overflow is detected, the receiver may not function correctly. // This compromises system reliability and can lead to undefined behavior. // To prevent further issues, execution is halted. - LOG(ERROR) << "Buffer Overflow Detected – Execution Halted"; - exit(1); + LOG(FATAL) << "Buffer Overflow Detected – Execution Halted"; } - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); + std::this_thread::sleep_for(std::chrono::milliseconds(BUFFER_MONITOR_PERIOD_ms)); std::lock_guard lock(buffer_monitor_mutex); if (enable_ovf_check_buffer_monitor_active_ == false) { diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h index fbb10bf67..12a03d86f 100644 --- a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h @@ -12,7 +12,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -63,20 +63,20 @@ public: gr::basic_block_sptr get_right_block() override; private: - const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); - const std::string default_rf_port_select = std::string("A_BALANCED"); - const std::string default_gain_mode = std::string("slow_attack"); - const double default_manual_gain_rx1 = 64.0; - const double default_manual_gain_rx2 = 64.0; - const uint64_t default_bandwidth = 12500000; + const std::string DEFAULT_NUM_FILENAME = std::string("FPGA_buffer_monitor_dump.dat"); + const std::string DEFAULT_RF_PORT_SELECT = std::string("A_BALANCED"); + const std::string DEFAULT_GAIN_MODE = std::string("slow_attack"); + const double DEFAULT_MANUAL_GAIN_RX1 = 64.0; + const double DEFAULT_MANUAL_GAIN_RX2 = 64.0; + const uint64_t DEFAULT_BANDWIDTH = 12500000; // perform dynamic bit selection every 500 ms by default - const uint32_t Gain_control_period_ms = 500; + const uint32_t GAIN_CONTROL_PERIOD_ms = 500; // check buffer overflow and perform buffer monitoring every 1s by default - const uint32_t buffer_monitor_period_ms = 1000; + const uint32_t BUFFER_MONITOR_PERIOD_ms = 1000; // buffer overflow and buffer monitoring initial delay - const uint32_t buffer_monitoring_initial_delay_ms = 2000; - const int32_t switch_to_real_time_mode = 2; + const uint32_t BUFFER_MONITOR_INITIAL_DELAY_ms = 2000; + const int32_t REAL_TIME_MODE = 2; void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); diff --git a/src/algorithms/signal_source/libs/fpga_dma-proxy.cc b/src/algorithms/signal_source/libs/fpga_dma-proxy.cc index 8ee7b411d..a02e04dbc 100644 --- a/src/algorithms/signal_source/libs/fpga_dma-proxy.cc +++ b/src/algorithms/signal_source/libs/fpga_dma-proxy.cc @@ -9,7 +9,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -22,68 +22,124 @@ #include // libraries used by the GIPO #include +Fpga_DMA::~Fpga_DMA() +{ + DMA_close(); +} + int Fpga_DMA::DMA_open() { - tx_channel.fd = open("/dev/dma_proxy_tx", O_RDWR); - if (tx_channel.fd < 1) + if (tx_channel.fd >= 0 || tx_channel.buf_ptr != nullptr) { - return tx_channel.fd; - } - - tx_channel.buf_ptr = (struct channel_buffer *)mmap(nullptr, sizeof(struct channel_buffer) * TX_BUFFER_COUNT, - PROT_READ | PROT_WRITE, MAP_SHARED, tx_channel.fd, 0); - if (tx_channel.buf_ptr == MAP_FAILED) - { - std::cerr << "Failed to mmap DMA tx channel\n" - << std::endl; + std::cerr << "DMA device is already open or has an active mapping\n"; return -1; } + tx_channel.fd = open("/dev/dma_proxy_tx", O_RDWR); + if (tx_channel.fd < 0) + { + return -1; + } + + void *mapping = mmap(nullptr, sizeof(channel_buffer) * TX_BUFFER_COUNT, + PROT_READ | PROT_WRITE, MAP_SHARED, tx_channel.fd, 0); + if (mapping == MAP_FAILED) + { + std::cerr << "Failed to mmap DMA tx channel\n"; + close(tx_channel.fd); + tx_channel.fd = -1; + return -1; + } + + tx_channel.buf_ptr = static_cast(mapping); return 0; } - -int8_t *Fpga_DMA::get_buffer_address() // NOLINT(readability-make-member-function-const) +int8_t *Fpga_DMA::get_buffer_address() const { + if (tx_channel.fd < 0 || tx_channel.buf_ptr == nullptr) + { + std::cerr << "DMA device is not open\n"; + return nullptr; + } return tx_channel.buf_ptr[0].buffer; } +uint32_t Fpga_DMA::get_buffer_size() const +{ + return DMA_MAX_BUFFER_SIZE; +} int Fpga_DMA::DMA_write(int nbytes) const { + if (tx_channel.fd < 0 || tx_channel.buf_ptr == nullptr) + { + std::cerr << "DMA device is not open\n"; + return -1; + } + if (nbytes <= 0 || static_cast(nbytes) > DMA_MAX_BUFFER_SIZE) + { + std::cerr << "Invalid DMA transfer size\n"; + return -1; + } + int buffer_id = 0; + tx_channel.buf_ptr[0].length = static_cast(nbytes); - tx_channel.buf_ptr[0].length = nbytes; - - // start DMA transfer - if (ioctl(tx_channel.fd, _IOW('a', 'b', int32_t *), &buffer_id)) // start transfer + // Start the transfer. These ioctl definitions must match the driver. + if (ioctl(tx_channel.fd, _IOW('a', 'b', int32_t *), &buffer_id)) { - std::cerr << "Error starting tx DMA transfer " << '\n'; + std::cerr << "Error starting tx DMA transfer\n"; return -1; } - // wait for completion of DMA transfer - if (ioctl(tx_channel.fd, _IOW('a', 'a', int32_t *), &buffer_id)) // finish transfer + // Wait for completion. + if (ioctl(tx_channel.fd, _IOW('a', 'a', int32_t *), &buffer_id)) { - std::cerr << "Error detecting end of DMA transfer " << '\n'; + std::cerr << "Error detecting end of DMA transfer\n"; return -1; } - if (tx_channel.buf_ptr[buffer_id].status) + if (buffer_id < 0 || static_cast(buffer_id) >= TX_BUFFER_COUNT) { - std::cerr << "Proxy DMA Tx transfer error " << '\n'; + std::cerr << "Invalid DMA buffer ID\n"; + return -1; + } + if (tx_channel.buf_ptr[buffer_id].status != channel_buffer::PROXY_NO_ERROR) + { + std::cerr << "Proxy DMA Tx transfer error\n"; return -1; } return 0; } - -int Fpga_DMA::DMA_close() const +int Fpga_DMA::DMA_close() { - if (munmap(tx_channel.buf_ptr, sizeof(struct channel_buffer))) + int result = 0; + if (tx_channel.buf_ptr != nullptr) { - std::cerr << "Failed to unmap DMA tx channel " << '\n'; - return -1; + if (munmap(tx_channel.buf_ptr, sizeof(channel_buffer) * TX_BUFFER_COUNT)) + { + std::cerr << "Failed to unmap DMA tx channel\n"; + result = -1; + } + else + { + tx_channel.buf_ptr = nullptr; + } } - return close(tx_channel.fd); + + // Attempt descriptor cleanup even if unmapping failed. + if (tx_channel.fd >= 0) + { + const int fd = tx_channel.fd; + tx_channel.fd = -1; + // Do not retry close(): on Linux the descriptor may already be released. + if (close(fd)) + { + std::cerr << "Failed to close DMA tx channel\n"; + result = -1; + } + } + return result; } diff --git a/src/algorithms/signal_source/libs/fpga_dma-proxy.h b/src/algorithms/signal_source/libs/fpga_dma-proxy.h index eb84aa682..491a864c3 100644 --- a/src/algorithms/signal_source/libs/fpga_dma-proxy.h +++ b/src/algorithms/signal_source/libs/fpga_dma-proxy.h @@ -9,7 +9,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -21,7 +21,7 @@ #include // for std::int8_t /*! - * \brief Class that controls the switch DMA in the FPGA + * \brief Class that controls DMA transfers to the FPGA */ class Fpga_DMA { @@ -32,9 +32,12 @@ public: Fpga_DMA() = default; /*! - * \brief Default destructor. + * \brief Release any open DMA resources. */ - ~Fpga_DMA() = default; + ~Fpga_DMA(); + + Fpga_DMA(const Fpga_DMA &) = delete; + Fpga_DMA &operator=(const Fpga_DMA &) = delete; /*! * \brief Open the DMA device driver. @@ -44,7 +47,12 @@ public: /*! * \brief Obtain DMA buffer address. */ - int8_t *get_buffer_address(void); // NOLINT(readability-make-member-function-const) + int8_t *get_buffer_address() const; + + /*! + * \brief Obtain DMA buffer size. + */ + uint32_t get_buffer_size() const; /*! * \brief Transfer DMA data @@ -54,7 +62,7 @@ public: /*! * \brief Close the DMA device driver */ - int DMA_close(void) const; + int DMA_close(void); private: static const uint32_t DMA_MAX_BUFFER_SIZE = (128 * 1024); /* must match driver exactly */ @@ -81,6 +89,6 @@ private: int fd; }; - channel tx_channel; + channel tx_channel{nullptr, -1}; }; #endif // GNSS_SDR_FPGA_DMA_PROXY_H diff --git a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc index 253b37de6..c4fa00d39 100644 --- a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc +++ b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.cc @@ -13,7 +13,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -35,28 +35,38 @@ Fpga_dynamic_bit_selection::Fpga_dynamic_bit_selection(bool enable_rx1_band, bool enable_rx2_band) : d_map_base_freq_band_1(nullptr), d_map_base_freq_band_2(nullptr), - d_dev_descr_freq_band_1(0), - d_dev_descr_freq_band_2(0), - d_shift_out_bits_freq_band_1(0), - d_shift_out_bits_freq_band_2(0), + d_dev_descr_freq_band_1(-1), + d_dev_descr_freq_band_2(-1), + d_shift_out_bits_freq_band_1(SHIFT_OUT_BITS_MAX_DEFAULT), + d_shift_out_bits_freq_band_2(SHIFT_OUT_BITS_MAX_DEFAULT), + d_shift_out_bit_max_band_1(SHIFT_OUT_BITS_MAX_DEFAULT), + d_shift_out_bit_max_band_2(SHIFT_OUT_BITS_MAX_DEFAULT), d_enable_rx1_band(enable_rx1_band), d_enable_rx2_band(enable_rx2_band) { if (d_enable_rx1_band) { - open_device(&d_map_base_freq_band_1, d_dev_descr_freq_band_1, 0); - - // init bit selection corresponding to frequency band 1 - d_shift_out_bits_freq_band_1 = shift_out_bits_default; - d_map_base_freq_band_1[0] = d_shift_out_bits_freq_band_1; + if (open_device(&d_map_base_freq_band_1, d_dev_descr_freq_band_1, SELECT_FREQ_BAND_1)) + { + // Read the maximum supported bit shift for frequency band 1 + initialize_device(d_map_base_freq_band_1, d_shift_out_bits_freq_band_1, d_shift_out_bit_max_band_1); + } + else + { + LOG(FATAL) << "Cannot initialize dynamic bit selection in frequency band 1"; + } } if (d_enable_rx2_band) { - open_device(&d_map_base_freq_band_2, d_dev_descr_freq_band_2, 1); - - // init bit selection corresponding to frequency band 2 - d_shift_out_bits_freq_band_2 = shift_out_bits_default; - d_map_base_freq_band_2[0] = d_shift_out_bits_freq_band_2; + if (open_device(&d_map_base_freq_band_2, d_dev_descr_freq_band_2, SELECT_FREQ_BAND_2)) + { + // Read the maximum supported bit shift for frequency band 2 + initialize_device(d_map_base_freq_band_2, d_shift_out_bits_freq_band_2, d_shift_out_bit_max_band_2); + } + else + { + LOG(FATAL) << "Cannot initialize dynamic bit selection in frequency band 2"; + } } DLOG(INFO) << "Dynamic bit selection FPGA class created"; } @@ -79,66 +89,86 @@ void Fpga_dynamic_bit_selection::bit_selection() { if (d_enable_rx1_band) { - bit_selection_per_rf_band(d_map_base_freq_band_1, d_shift_out_bits_freq_band_1); + bit_selection_per_rf_band(d_map_base_freq_band_1, d_shift_out_bits_freq_band_1, d_shift_out_bit_max_band_1); } if (d_enable_rx2_band) { - bit_selection_per_rf_band(d_map_base_freq_band_2, d_shift_out_bits_freq_band_2); + bit_selection_per_rf_band(d_map_base_freq_band_2, d_shift_out_bits_freq_band_2, d_shift_out_bit_max_band_2); } } -void Fpga_dynamic_bit_selection::open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band) +bool Fpga_dynamic_bit_selection::open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band) { - // find the uio device file corresponding to the dynamic bit selector 0 module. + // Find the UIO device for the selected frequency band. std::string device_name; - if (find_uio_dev_file_name(device_name, dyn_bit_sel_device_name, freq_band) < 0) + const int device_num = freq_band - 1; + if (find_uio_dev_file_name(device_name, DYN_BIT_SEL_DEV_NAME, device_num) < 0) { - std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n'; - std::cout << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n'; - return; + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << DYN_BIT_SEL_DEV_NAME << " in frequency band " << freq_band << '\n'; + return false; } - // dynamic bits selection corresponding to frequency band 1 + // Open the dynamic bit selection device. if ((d_dev_descr = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) { - LOG(WARNING) << "Cannot open deviceio" << device_name; - std::cout << "Cannot open deviceio" << device_name << std::endl; + std::cerr << "Cannot open deviceio " << device_name << std::endl; + return false; } - *d_map_base = reinterpret_cast(mmap(nullptr, FPGA_PAGE_SIZE, + volatile void *map_base = reinterpret_cast(mmap(nullptr, FPGA_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, d_dev_descr, 0)); - if (*d_map_base == reinterpret_cast(-1)) + if (map_base == MAP_FAILED) { - LOG(WARNING) << "Cannot map the FPGA dynamic bit selection module in frequency band 1 into tracking memory"; - std::cout << "Could not map dynamic bit selection memory corresponding to frequency band 1.\n"; + std::cerr << "Could not map dynamic bit selection memory corresponding to frequency band " << freq_band << ".\n"; + close(d_dev_descr); + d_dev_descr = -1; + return false; } + *d_map_base = reinterpret_cast(map_base); + + return true; } +void Fpga_dynamic_bit_selection::initialize_device(volatile unsigned *d_map_base, uint32_t &shift_out_bits, uint32_t &shift_out_bit_max) +{ + // Read the IP core version + uint32_t IP_core_version = d_map_base[FPGA_IP_CORE_VERSION_REG_ADDR]; -void Fpga_dynamic_bit_selection::bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t &shift_out_bits) + if (IP_core_version == FPGA_DYN_BIT_SEL_IP_VERSION_1_2) + { + // Read the maximum supported bit shift. + // Previous versions of the IP core are initialized to SHIFT_OUT_BITS_MAX_DEFAULT + shift_out_bit_max = static_cast(d_map_base[MAX_BIT_SHIFT_REG_ADDR]); + shift_out_bits = shift_out_bit_max; + } + // Initialize dynamic bit selection to the maximum supported shift. + d_map_base[SOBITS_REG_ADDR] = shift_out_bits; +} + +void Fpga_dynamic_bit_selection::bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t &shift_out_bits, uint32_t shift_out_bit_max) { // estimated signal power - uint32_t rx_signal_power = d_map_base[1]; + uint32_t rx_signal_power = d_map_base[SIGPOW_REG_ADDR]; // dynamic bit selection - if (rx_signal_power > Power_Threshold_High) + if (rx_signal_power > POWER_THRESHOLD_HIGH) { if (shift_out_bits < shift_out_bit_max) { shift_out_bits = shift_out_bits + 1; } } - else if (rx_signal_power < Power_Threshold_Low) + else if (rx_signal_power < POWER_THRESHOLD_LOW) { - if (shift_out_bits > shift_out_bits_min) + if (shift_out_bits > SHIFT_OUT_BITS_MIN) { shift_out_bits = shift_out_bits - 1; } } - // update bit selection corresponding to frequency band 1 - d_map_base[0] = shift_out_bits; + // Update bit selection for the selected frequency band. + d_map_base[SOBITS_REG_ADDR] = shift_out_bits; } @@ -150,4 +180,4 @@ void Fpga_dynamic_bit_selection::close_device(volatile unsigned *d_map_base, int std::cout << "Failed to unmap memory uio\n"; } close(d_dev_descr); -} \ No newline at end of file +} diff --git a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h index c53aee292..f4990a894 100644 --- a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h +++ b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h @@ -13,7 +13,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -25,7 +25,6 @@ #include #include #include -#include /** \addtogroup Signal_Source * \{ */ @@ -34,8 +33,7 @@ /*! - * \brief Class that controls the switch in the FPGA, which connects the FPGA acquisition and multicorrelator modules to - * either the DMA or the Analog Front-End. + * \brief Controls dynamic bit selection in the FPGA. */ class Fpga_dynamic_bit_selection { @@ -50,26 +48,45 @@ public: */ ~Fpga_dynamic_bit_selection(); + // Prevent copying objects that own FPGA mappings and file descriptors. + Fpga_dynamic_bit_selection(const Fpga_dynamic_bit_selection &) = delete; + Fpga_dynamic_bit_selection &operator=(const Fpga_dynamic_bit_selection &) = delete; + + /*! - * \brief This function configures the switch in th eFPGA + * \brief Adjusts the bit shift for each enabled frequency band based on signal power. */ void bit_selection(void); private: - const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name - static const size_t FPGA_PAGE_SIZE = 0x1000; - static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC - static const uint32_t Num_bits_FPGA = 4; // Number of bits after the bit selection - static const uint32_t shift_out_bits_default = Num_bits_ADC - Num_bits_FPGA; // take the most significant bits by default - static const uint32_t shift_out_bits_min = 0; // minimum possible value for the bit selection - static const uint32_t shift_out_bit_max = Num_bits_ADC - Num_bits_FPGA; // maximum possible value for the bit selection - // received signal power thresholds for the bit selection - // the received signal power is estimated as the averaged squared absolute value of the received signal samples - static const uint32_t Power_Threshold_High = 9000; - static const uint32_t Power_Threshold_Low = 3000; + // IP core device name + const std::string DYN_BIT_SEL_DEV_NAME = std::string("dynamic_bits_selector"); // Dynamic bit selection device name - void open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band); - void bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t &shift_out_bits); + // IP Core version + const uint32_t FPGA_DYN_BIT_SEL_IP_VERSION_1_2 = 0x0002; // Dynamic bit selection IP core version 1.2 + + // page size + static const size_t FPGA_PAGE_SIZE = 0x1000; + + // write-only registers + static const uint32_t SOBITS_REG_ADDR = 0; // number of shift bits + + // read-only registers + static const uint32_t FPGA_IP_CORE_VERSION_REG_ADDR = 0; // IP core version register address + static const uint32_t SIGPOW_REG_ADDR = 1; // rx signal power + static const uint32_t MAX_BIT_SHIFT_REG_ADDR = 2; // maximum number of shift bits + + // dynamic bit selection parameters + static const uint32_t SELECT_FREQ_BAND_1 = 1; // selection for frequency band 1 + static const uint32_t SELECT_FREQ_BAND_2 = 2; // selection for frequency band 2 + static const uint32_t SHIFT_OUT_BITS_MAX_DEFAULT = 8; // take the most significant bits by default + static const uint32_t SHIFT_OUT_BITS_MIN = 0; // minimum possible value for the bit selection + static const uint32_t POWER_THRESHOLD_HIGH = 9000; + static const uint32_t POWER_THRESHOLD_LOW = 3000; + + bool open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band); + void initialize_device(volatile unsigned *d_map_base, uint32_t &shift_out_bits, uint32_t &shift_out_bit_max); + void bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t &shift_out_bits, uint32_t shift_out_bit_max); void close_device(volatile unsigned *d_map_base, int &d_dev_descr); volatile unsigned *d_map_base_freq_band_1; @@ -78,6 +95,8 @@ private: int d_dev_descr_freq_band_2; uint32_t d_shift_out_bits_freq_band_1; uint32_t d_shift_out_bits_freq_band_2; + uint32_t d_shift_out_bit_max_band_1; + uint32_t d_shift_out_bit_max_band_2; bool d_enable_rx1_band; bool d_enable_rx2_band; };