mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-10-09 09:11:51 +00:00
Merge branch 'refactor/fpga-signal-sources' of https://github.com/mmajoral/gnss-sdr into mmajoral-refactor/fpga-signal-sources
This commit is contained in:
@@ -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<pmt::pmt_t> *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<uint64_t>(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))),
|
||||
tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(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<uint64_t>(GPS_L1_FREQ_HZ));
|
||||
}
|
||||
|
||||
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||
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<Fpga_Switch>();
|
||||
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<Fpga_buffer_monitor>(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<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band);
|
||||
dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(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<std::mutex> 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<std::mutex> lock(buffer_monitor_mutex);
|
||||
if (enable_ovf_check_buffer_monitor_active_ == false)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <algorithm> // for std::min
|
||||
#include <chrono> // for std::chrono
|
||||
#include <cmath> // for std::isfinite
|
||||
#include <fcntl.h> // for open, O_WRONLY
|
||||
#include <fstream> // for std::ifstream
|
||||
#include <iomanip> // for std::setprecision
|
||||
#include <iostream> // for std::cout
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <vector> // fr std::vector
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
@@ -43,9 +45,9 @@ DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configura
|
||||
Concurrent_Queue<pmt::pmt_t> *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<int64_t>(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<uint64_t>(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<long double>(seconds_to_skip) * sample_rate_;
|
||||
// Leave room for the header and keep ignore()'s byte count representable.
|
||||
CHECK(static_cast<long double>(header_size) <
|
||||
static_cast<long double>(std::numeric_limits<std::streamsize>::max()))
|
||||
<< "Header size is too large.";
|
||||
CHECK(samples_to_skip <
|
||||
(static_cast<long double>(std::numeric_limits<std::streamsize>::max()) -
|
||||
header_size) /
|
||||
bytes_per_sample)
|
||||
<< "Requested skip is too large.";
|
||||
bytes_to_skip_ = static_cast<uint64_t>(samples_to_skip) * bytes_per_sample +
|
||||
header_size;
|
||||
|
||||
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||
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<double>(size) / static_cast<double>(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<double>(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<uint64_t>(size) - bytes_to_skip;
|
||||
samples_ = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(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<double>(size) / static_cast<double>(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<double>(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<uint64_t>(size) - bytes_to_skip;
|
||||
samples_rx2 = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(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<uint64_t>(std::numeric_limits<int64_t>::max()))
|
||||
<< "Input sample count is too large.";
|
||||
samples_ = static_cast<int64_t>(items_to_process);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(static_cast<uint64_t>(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<double>(samples_) * (1 / static_cast<double>(sample_rate_))) / 2.0;
|
||||
double signal_duration_s = (static_cast<double>(samples_) * (1 / static_cast<double>(sample_rate_))) / static_cast<double>(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<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band);
|
||||
dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(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<uint64_t>(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<pmt::pmt_t> *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<pmt::pmt_t> *queue)
|
||||
{
|
||||
std::ifstream infile1;
|
||||
infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
|
||||
|
||||
// FPGA DMA control
|
||||
dma_fpga = std::make_shared<Fpga_DMA>();
|
||||
|
||||
@@ -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<int8_t> 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<int8_t> 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<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
|
||||
if (enable_dynamic_bit_selection_ == false)
|
||||
{
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
@@ -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<pmt::pmt_t> *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<uint64_t>(GPS_L1_FREQ_HZ))),
|
||||
freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(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<float>(0.0))),
|
||||
Fstop_(configuration->property(role + ".Fstop", static_cast<float>(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<Fpga_Switch>();
|
||||
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<Fpga_Switch>();
|
||||
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<Fpga_buffer_monitor>(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<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band);
|
||||
dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(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<std::mutex> 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<std::mutex> lock(buffer_monitor_mutex);
|
||||
if (enable_ovf_check_buffer_monitor_active_ == false)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <sys/mman.h> // libraries used by the GIPO
|
||||
#include <unistd.h>
|
||||
|
||||
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<channel_buffer *>(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<uint32_t>(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<unsigned int>(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<uint32_t>(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;
|
||||
}
|
||||
|
||||
@@ -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 <cstdint> // 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
|
||||
|
||||
@@ -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<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
|
||||
volatile void *map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, d_dev_descr, 0));
|
||||
|
||||
if (*d_map_base == reinterpret_cast<void *>(-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<volatile unsigned *>(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<uint32_t>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user