Merge branch 'refactor/fpga-signal-sources' of https://github.com/mmajoral/gnss-sdr into mmajoral-refactor/fpga-signal-sources

This commit is contained in:
Carles Fernandez
2026-10-02 11:32:16 +02:00
10 changed files with 458 additions and 339 deletions
@@ -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;
};