mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-12 11:10:33 +00:00
Decouple the FPGA DMA signal source from the AD9361 FPGA signal source.
This commit is contained in:
parent
20d664a8b7
commit
ac7bdc919b
@ -41,6 +41,14 @@ if(ENABLE_AD9361)
|
|||||||
list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h)
|
list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_FPGA)
|
||||||
|
###############################################
|
||||||
|
# FPGA DMA source
|
||||||
|
###############################################
|
||||||
|
list(APPEND OPT_DRIVER_SOURCES dma_fpga_signal_source.cc)
|
||||||
|
list(APPEND OPT_DRIVER_HEADERS dma_fpga_signal_source.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND)
|
if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND)
|
||||||
list(APPEND OPT_DRIVER_SOURCES flexiband_signal_source.cc)
|
list(APPEND OPT_DRIVER_SOURCES flexiband_signal_source.cc)
|
||||||
list(APPEND OPT_DRIVER_HEADERS flexiband_signal_source.h)
|
list(APPEND OPT_DRIVER_HEADERS flexiband_signal_source.h)
|
||||||
|
@ -26,22 +26,14 @@
|
|||||||
#include "GPS_L1_CA.h"
|
#include "GPS_L1_CA.h"
|
||||||
#include "GPS_L5.h"
|
#include "GPS_L5.h"
|
||||||
#include "ad9361_manager.h"
|
#include "ad9361_manager.h"
|
||||||
#include "command_event.h"
|
|
||||||
#include "configuration_interface.h"
|
#include "configuration_interface.h"
|
||||||
#include "gnss_sdr_flags.h"
|
#include "gnss_sdr_flags.h"
|
||||||
#include "gnss_sdr_string_literals.h"
|
#include "gnss_sdr_string_literals.h"
|
||||||
#include "uio_fpga.h"
|
|
||||||
#include <iio.h>
|
|
||||||
#include <algorithm> // for std::max
|
#include <algorithm> // for std::max
|
||||||
#include <chrono> // for std::chrono
|
#include <chrono> // for std::chrono
|
||||||
#include <cmath> // for std::floor
|
#include <cmath> // for std::floor
|
||||||
#include <exception> // for std::exception
|
#include <exception> // for std::exception
|
||||||
#include <fcntl.h> // for open, O_WRONLY
|
|
||||||
#include <fstream> // for std::ifstream
|
|
||||||
#include <iomanip> // for std::setprecision
|
|
||||||
#include <iostream> // for std::cout
|
#include <iostream> // for std::cout
|
||||||
#include <unistd.h> // for write
|
|
||||||
#include <vector> // fr std::vector
|
|
||||||
|
|
||||||
#if USE_GLOG_AND_GFLAGS
|
#if USE_GLOG_AND_GFLAGS
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
@ -56,12 +48,10 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con
|
|||||||
const std::string &role, unsigned int in_stream, unsigned int out_stream,
|
const std::string &role, unsigned int in_stream, unsigned int out_stream,
|
||||||
Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused)))
|
Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused)))
|
||||||
: SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s),
|
: SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s),
|
||||||
queue_(queue),
|
|
||||||
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)),
|
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)),
|
||||||
gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", 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)),
|
rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)),
|
||||||
filter_filename_(configuration->property(role + ".filter_filename", filter_file_)),
|
filter_filename_(configuration->property(role + ".filter_filename", filter_file_)),
|
||||||
filename0_(configuration->property(role + ".filename", empty_string)),
|
|
||||||
rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)),
|
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_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)),
|
||||||
scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)),
|
scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)),
|
||||||
@ -71,18 +61,13 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con
|
|||||||
freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))),
|
freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))),
|
||||||
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
|
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
|
||||||
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
|
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
|
||||||
samples_to_skip_(0),
|
|
||||||
samples_(configuration->property(role + ".samples", static_cast<int64_t>(0))),
|
|
||||||
freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))),
|
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_))),
|
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))),
|
tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(500000))),
|
||||||
Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))),
|
Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))),
|
||||||
Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))),
|
Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))),
|
||||||
num_input_files_(1),
|
|
||||||
dma_buff_offset_pos_(0),
|
|
||||||
in_stream_(in_stream),
|
in_stream_(in_stream),
|
||||||
out_stream_(out_stream),
|
out_stream_(out_stream),
|
||||||
switch_position_(configuration->property(role + ".switch_position", 0)),
|
|
||||||
item_size_(sizeof(int8_t)),
|
item_size_(sizeof(int8_t)),
|
||||||
enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)),
|
enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)),
|
||||||
filter_auto_(configuration->property(role + ".filter_auto", false)),
|
filter_auto_(configuration->property(role + ".filter_auto", false)),
|
||||||
@ -91,20 +76,15 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con
|
|||||||
bb_dc_(configuration->property(role + ".bb_dc", true)),
|
bb_dc_(configuration->property(role + ".bb_dc", true)),
|
||||||
rx1_enable_(configuration->property(role + ".rx1_enable", true)),
|
rx1_enable_(configuration->property(role + ".rx1_enable", true)),
|
||||||
rx2_enable_(configuration->property(role + ".rx2_enable", true)),
|
rx2_enable_(configuration->property(role + ".rx2_enable", true)),
|
||||||
enable_DMA_(false),
|
|
||||||
enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)),
|
enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)),
|
||||||
enable_ovf_check_buffer_monitor_active_(false),
|
enable_ovf_check_buffer_monitor_active_(true),
|
||||||
dump_(configuration->property(role + ".dump", false)),
|
dump_(configuration->property(role + ".dump", false)),
|
||||||
#if USE_GLOG_AND_GFLAGS
|
#if USE_GLOG_AND_GFLAGS
|
||||||
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)),
|
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown))
|
||||||
#else
|
#else
|
||||||
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))),
|
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown)))
|
||||||
#endif
|
#endif
|
||||||
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) ||
|
const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) ||
|
||||||
(configuration->property("Channels_1B.count", 0) > 0));
|
(configuration->property("Channels_1B.count", 0) > 0));
|
||||||
const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) ||
|
const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) ||
|
||||||
@ -126,328 +106,158 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con
|
|||||||
{
|
{
|
||||||
filter_source_ = configuration->property(role + ".filter_source", std::string("Off"));
|
filter_source_ = configuration->property(role + ".filter_source", std::string("Off"));
|
||||||
}
|
}
|
||||||
#if USE_GLOG_AND_GFLAGS
|
|
||||||
// override value with commandline flag, if present
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
if (FLAGS_signal_source != "-")
|
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"))
|
||||||
{
|
{
|
||||||
filename0_ = FLAGS_signal_source;
|
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;
|
||||||
}
|
}
|
||||||
if (FLAGS_s != "-")
|
|
||||||
|
if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid"))
|
||||||
{
|
{
|
||||||
filename0_ = FLAGS_s;
|
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;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (absl::GetFlag(FLAGS_signal_source) != "-")
|
if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid"))
|
||||||
{
|
{
|
||||||
filename0_ = absl::GetFlag(FLAGS_signal_source);
|
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;
|
||||||
}
|
}
|
||||||
if (absl::GetFlag(FLAGS_s) != "-")
|
|
||||||
|
if (gain_mode_rx1_ == "manual")
|
||||||
{
|
{
|
||||||
filename0_ = absl::GetFlag(FLAGS_s);
|
if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0)
|
||||||
}
|
|
||||||
#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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (gain_mode_rx2_ == "manual")
|
||||||
{
|
{
|
||||||
dma_buff_offset_pos_ = 2;
|
if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seconds_to_skip > 0)
|
if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design"))
|
||||||
{
|
{
|
||||||
samples_to_skip_ = static_cast<uint64_t>(seconds_to_skip * sample_rate_) * 2;
|
std::cout << "Configuration parameter filter_source should take one of these values:\n";
|
||||||
}
|
std::cout << " Off: Disable filter\n";
|
||||||
if (header_size > 0)
|
std::cout << " Auto: Use auto-generated filters\n";
|
||||||
{
|
std::cout << " File: User-provided filter in filter_filename parameter\n";
|
||||||
samples_to_skip_ += header_size;
|
std::cout << " Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n";
|
||||||
|
std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n";
|
||||||
|
std::cout << " This parameter has been set to its default value filter_source=Off\n";
|
||||||
|
filter_source_ = std::string("Off");
|
||||||
|
LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string device_io_name; // Switch UIO device file
|
if (bandwidth_ < 200000 || bandwidth_ > 56000000)
|
||||||
// find the uio device file corresponding to the switch.
|
|
||||||
if (find_uio_dev_file_name(device_io_name, switch_device_name, 0) < 0)
|
|
||||||
{
|
{
|
||||||
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << '\n';
|
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 << "LO frequency : " << freq0_ << " Hz\n";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
config_ad9361_rx_local(bandwidth_,
|
||||||
|
sample_rate_,
|
||||||
|
freq0_,
|
||||||
|
freq1_,
|
||||||
|
rf_port_select_,
|
||||||
|
rx1_enable_,
|
||||||
|
rx2_enable_,
|
||||||
|
gain_mode_rx1_,
|
||||||
|
gain_mode_rx2_,
|
||||||
|
rf_gain_rx1_,
|
||||||
|
rf_gain_rx2_,
|
||||||
|
quadrature_,
|
||||||
|
rf_dc_,
|
||||||
|
bb_dc_,
|
||||||
|
filter_source_,
|
||||||
|
filter_filename_,
|
||||||
|
Fpass_,
|
||||||
|
Fstop_);
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION
|
||||||
if (switch_position_ != 0 && switch_position_ != 2)
|
if (enable_dds_lo_ == true)
|
||||||
{
|
{
|
||||||
std::cout << "SignalSource.switch_position configuration parameter must be either 0: read from file(s) via DMA, or 2: read from AD9361\n";
|
if (tx_bandwidth_ < static_cast<uint64_t>(std::floor(static_cast<float>(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000))
|
||||||
std::cout << "SignalSource.switch_position configuration parameter set to its default value switch_position=0 - read from file(s)\n";
|
|
||||||
switch_position_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_fpga = std::make_shared<Fpga_Switch>(device_io_name);
|
|
||||||
switch_fpga->set_switch_position(switch_position_);
|
|
||||||
|
|
||||||
if (switch_position_ == 0) // Inject file(s) via DMA
|
|
||||||
{
|
|
||||||
enable_DMA_ = true;
|
|
||||||
|
|
||||||
if (samples_ == 0) // read all file
|
|
||||||
{
|
{
|
||||||
/*!
|
std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast<float>(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n";
|
||||||
* BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File.
|
std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n";
|
||||||
* A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the
|
std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n";
|
||||||
* valve block
|
tx_bandwidth_ = 500000;
|
||||||
*/
|
LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000";
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75)
|
||||||
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;
|
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
if (filename1_.empty())
|
|
||||||
{
|
{
|
||||||
DLOG(INFO) << "File source filename " << filename0_;
|
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;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
DLOG(INFO) << "File source filename rx1 " << filename0_;
|
|
||||||
DLOG(INFO) << "File source filename rx2 " << filename1_;
|
|
||||||
}
|
|
||||||
DLOG(INFO) << "Samples " << samples_;
|
|
||||||
DLOG(INFO) << "Sampling frequency " << sample_rate_;
|
|
||||||
DLOG(INFO) << "Item type " << std::string("ibyte");
|
|
||||||
DLOG(INFO) << "Item size " << item_size_;
|
|
||||||
DLOG(INFO) << "Repeat " << repeat_;
|
|
||||||
}
|
|
||||||
if (switch_position_ == 2) // Real-time via AD9361
|
|
||||||
{
|
|
||||||
std::cout << "Sample rate: " << sample_rate_ << " Sps\n";
|
|
||||||
|
|
||||||
enable_ovf_check_buffer_monitor_active_ = false; // check buffer overflow and buffer monitor disabled by default
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid"))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid"))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gain_mode_rx1_ == "manual")
|
|
||||||
{
|
|
||||||
if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gain_mode_rx2_ == "manual")
|
|
||||||
{
|
|
||||||
if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design"))
|
|
||||||
{
|
|
||||||
std::cout << "Configuration parameter filter_source should take one of these values:\n";
|
|
||||||
std::cout << " Off: Disable filter\n";
|
|
||||||
std::cout << " Auto: Use auto-generated filters\n";
|
|
||||||
std::cout << " File: User-provided filter in filter_filename parameter\n";
|
|
||||||
std::cout << " Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n";
|
|
||||||
std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n";
|
|
||||||
std::cout << " This parameter has been set to its default value filter_source=Off\n";
|
|
||||||
filter_source_ = std::string("Off");
|
|
||||||
LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bandwidth_ < 200000 || bandwidth_ > 56000000)
|
|
||||||
{
|
|
||||||
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 << "LO frequency : " << freq0_ << " Hz\n";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config_ad9361_rx_local(bandwidth_,
|
config_ad9361_lo_local(tx_bandwidth_,
|
||||||
sample_rate_,
|
sample_rate_,
|
||||||
freq0_,
|
freq_rf_tx_hz_,
|
||||||
freq1_,
|
tx_attenuation_db_,
|
||||||
rf_port_select_,
|
freq_dds_tx_hz_,
|
||||||
rx1_enable_,
|
scale_dds_dbfs_,
|
||||||
rx2_enable_,
|
phase_dds_deg_);
|
||||||
gain_mode_rx1_,
|
|
||||||
gain_mode_rx2_,
|
|
||||||
rf_gain_rx1_,
|
|
||||||
rf_gain_rx2_,
|
|
||||||
quadrature_,
|
|
||||||
rf_dc_,
|
|
||||||
bb_dc_,
|
|
||||||
filter_source_,
|
|
||||||
filter_filename_,
|
|
||||||
Fpass_,
|
|
||||||
Fstop_);
|
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error &e)
|
catch (const std::runtime_error &e)
|
||||||
{
|
{
|
||||||
std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n';
|
std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION
|
|
||||||
if (enable_dds_lo_ == true)
|
|
||||||
{
|
|
||||||
if (tx_bandwidth_ < static_cast<uint64_t>(std::floor(static_cast<float>(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000))
|
|
||||||
{
|
|
||||||
std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast<float>(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n";
|
|
||||||
std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n";
|
|
||||||
std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n";
|
|
||||||
tx_bandwidth_ = 500000;
|
|
||||||
LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000";
|
|
||||||
}
|
|
||||||
if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
config_ad9361_lo_local(tx_bandwidth_,
|
|
||||||
sample_rate_,
|
|
||||||
freq_rf_tx_hz_,
|
|
||||||
tx_attenuation_db_,
|
|
||||||
freq_dds_tx_hz_,
|
|
||||||
scale_dds_dbfs_,
|
|
||||||
phase_dds_deg_);
|
|
||||||
}
|
|
||||||
catch (const std::runtime_error &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when the receiver is working in real-time mode via AD9361 perform buffer overflow checking,
|
|
||||||
// and if dump is enabled perform buffer monitoring
|
|
||||||
enable_ovf_check_buffer_monitor_active_ = true;
|
|
||||||
|
|
||||||
std::string device_io_name_buffer_monitor;
|
|
||||||
|
|
||||||
std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename);
|
|
||||||
|
|
||||||
// find the uio device file corresponding to the buffer monitor
|
|
||||||
if (find_uio_dev_file_name(device_io_name_buffer_monitor, buffer_monitor_device_name, 0) < 0)
|
|
||||||
{
|
|
||||||
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << buffer_monitor_device_name << '\n';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(device_io_name_buffer_monitor, num_freq_bands, dump_, dump_filename);
|
|
||||||
thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(); });
|
||||||
|
|
||||||
|
|
||||||
// dynamic bits selection
|
// dynamic bits selection
|
||||||
if (enable_dynamic_bit_selection_)
|
if (enable_dynamic_bit_selection_)
|
||||||
{
|
{
|
||||||
@ -469,53 +279,40 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con
|
|||||||
Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource()
|
Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource()
|
||||||
{
|
{
|
||||||
/* cleanup and exit */
|
/* cleanup and exit */
|
||||||
if (switch_position_ == 0) // read samples from a file via DMA
|
|
||||||
|
if (rf_shutdown_)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(dma_mutex);
|
std::cout << "* AD9361 Disabling RX streaming channels\n";
|
||||||
enable_DMA_ = false; // disable the DMA
|
if (!disable_ad9361_rx_local())
|
||||||
lock.unlock();
|
|
||||||
if (thread_file_to_dma.joinable())
|
|
||||||
{
|
{
|
||||||
thread_file_to_dma.join();
|
LOG(WARNING) << "Problem shutting down the AD9361 RX channels";
|
||||||
|
}
|
||||||
|
if (enable_dds_lo_)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ad9361_disable_lo_local();
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switch_position_ == 2) // Real-time via AD9361
|
// disable buffer overflow checking and buffer monitoring
|
||||||
|
std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
|
||||||
|
enable_ovf_check_buffer_monitor_active_ = false;
|
||||||
|
lock_buffer_monitor.unlock();
|
||||||
|
|
||||||
|
if (thread_buffer_monitor.joinable())
|
||||||
{
|
{
|
||||||
if (rf_shutdown_)
|
thread_buffer_monitor.join();
|
||||||
{
|
|
||||||
std::cout << "* AD9361 Disabling RX streaming channels\n";
|
|
||||||
if (!disable_ad9361_rx_local())
|
|
||||||
{
|
|
||||||
LOG(WARNING) << "Problem shutting down the AD9361 RX channels";
|
|
||||||
}
|
|
||||||
if (enable_dds_lo_)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ad9361_disable_lo_local();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable buffer overflow checking and buffer monitoring
|
|
||||||
std::unique_lock<std::mutex> lock(buffer_monitor_mutex);
|
|
||||||
enable_ovf_check_buffer_monitor_active_ = false;
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
if (thread_buffer_monitor.joinable())
|
|
||||||
{
|
|
||||||
thread_buffer_monitor.join();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex);
|
std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
|
||||||
bool bit_selection_enabled = enable_dynamic_bit_selection_;
|
bool bit_selection_enabled = enable_dynamic_bit_selection_;
|
||||||
lock.unlock();
|
lock_dyn_bit_sel.unlock();
|
||||||
|
|
||||||
if (bit_selection_enabled == true)
|
if (bit_selection_enabled == true)
|
||||||
{
|
{
|
||||||
@ -531,290 +328,6 @@ Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ad9361FpgaSignalSource::start()
|
|
||||||
{
|
|
||||||
thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Ad9361FpgaSignalSource::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)
|
|
||||||
{
|
|
||||||
std::ifstream infile1;
|
|
||||||
infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
||||||
|
|
||||||
|
|
||||||
// FPGA DMA control
|
|
||||||
dma_fpga = std::make_shared<Fpga_DMA>();
|
|
||||||
|
|
||||||
// open the files
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.open(filename0_, std::ios::binary);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception opening file " << filename0_ << '\n';
|
|
||||||
// stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream infile2;
|
|
||||||
if (!filename1_.empty())
|
|
||||||
{
|
|
||||||
infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.open(filename1_, std::ios::binary);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception opening file " << filename1_ << '\n';
|
|
||||||
// stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip the initial samples if needed
|
|
||||||
uint64_t bytes_to_skeep = samples_to_skip * item_size;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.ignore(bytes_to_skeep);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception skipping initial samples file " << filename0_ << '\n';
|
|
||||||
// stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filename1_.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.ignore(bytes_to_skeep);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception skipping initial samples file " << filename1_ << '\n';
|
|
||||||
// stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rx signal vectors
|
|
||||||
std::vector<int8_t> input_samples(sample_block_size * 2); // complex samples
|
|
||||||
// pointer to DMA buffer
|
|
||||||
int8_t *dma_buffer;
|
|
||||||
int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1
|
|
||||||
bool run_DMA = true;
|
|
||||||
|
|
||||||
// Open DMA device
|
|
||||||
if (dma_fpga->DMA_open())
|
|
||||||
{
|
|
||||||
std::cerr << "Cannot open loop device\n";
|
|
||||||
// stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dma_buffer = dma_fpga->get_buffer_address();
|
|
||||||
|
|
||||||
// if only one frequency band is used then clear the samples corresponding to the unused frequency band
|
|
||||||
uint32_t dma_index = 0;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0;
|
|
||||||
dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0;
|
|
||||||
dma_index += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t nbytes_remaining = samples * item_size;
|
|
||||||
uint32_t read_buffer_size = sample_block_size * 2; // complex samples
|
|
||||||
|
|
||||||
// run the DMA
|
|
||||||
while (run_DMA)
|
|
||||||
{
|
|
||||||
dma_index = 0;
|
|
||||||
if (nbytes_remaining < read_buffer_size)
|
|
||||||
{
|
|
||||||
read_buffer_size = nbytes_remaining;
|
|
||||||
}
|
|
||||||
nbytes_remaining = nbytes_remaining - read_buffer_size;
|
|
||||||
|
|
||||||
// read filename 0
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception reading file " << filename0_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (infile1)
|
|
||||||
{
|
|
||||||
nread_elements = read_buffer_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// FLAG AS ERROR !! IT SHOULD NEVER HAPPEN
|
|
||||||
nread_elements = infile1.gcount();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index0 = 0; index0 < (nread_elements); index0 += 2)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read filename 1 (if enabled)
|
|
||||||
if (num_input_files_ > 1)
|
|
||||||
{
|
|
||||||
dma_index = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception reading file " << filename1_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (infile2)
|
|
||||||
{
|
|
||||||
nread_elements = read_buffer_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// FLAG AS ERROR !! IT SHOULD NEVER HAPPEN
|
|
||||||
nread_elements = infile2.gcount();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index0 = 0; index0 < (nread_elements); index0 += 2)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nread_elements > 0)
|
|
||||||
{
|
|
||||||
if (dma_fpga->DMA_write(nread_elements * 2))
|
|
||||||
{
|
|
||||||
std::cerr << "Error: DMA could not send all the required samples\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Throttle the DMA
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes_remaining == 0)
|
|
||||||
{
|
|
||||||
if (repeat)
|
|
||||||
{
|
|
||||||
// read the file again
|
|
||||||
nbytes_remaining = samples * item_size;
|
|
||||||
read_buffer_size = sample_block_size * 2;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.seekg(0);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip the initial samples if needed
|
|
||||||
uint64_t bytes_to_skeep = samples_to_skip * item_size;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.ignore(bytes_to_skeep);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception skipping initial samples file " << filename0_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filename1_.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.seekg(0);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.ignore(bytes_to_skeep);
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception skipping initial samples file " << filename1_ << '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the input file is completely processed. Stop the receiver.
|
|
||||||
run_DMA = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::unique_lock<std::mutex> lock(dma_mutex);
|
|
||||||
if (enable_DMA_ == false)
|
|
||||||
{
|
|
||||||
run_DMA = false;
|
|
||||||
}
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dma_fpga->DMA_close())
|
|
||||||
{
|
|
||||||
std::cerr << "Error closing loop device " << '\n';
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile1.close();
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception closing file " << filename0_ << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_input_files_ > 1)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
infile2.close();
|
|
||||||
}
|
|
||||||
catch (const std::ifstream::failure &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Exception closing file " << filename1_ << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop the receiver
|
|
||||||
queue->push(pmt::make_any(command_event_make(200, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process()
|
void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process()
|
||||||
{
|
{
|
||||||
bool dynamic_bit_selection_active = true;
|
bool dynamic_bit_selection_active = true;
|
||||||
|
@ -53,8 +53,6 @@ public:
|
|||||||
|
|
||||||
~Ad9361FpgaSignalSource();
|
~Ad9361FpgaSignalSource();
|
||||||
|
|
||||||
void start() override;
|
|
||||||
|
|
||||||
inline size_t item_size() override
|
inline size_t item_size() override
|
||||||
{
|
{
|
||||||
return item_size_;
|
return item_size_;
|
||||||
@ -66,13 +64,9 @@ public:
|
|||||||
gr::basic_block_sptr get_right_block() override;
|
gr::basic_block_sptr get_right_block() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
|
|
||||||
const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
|
|
||||||
const std::string buffer_monitor_device_name = std::string("buffer_monitor"); // buffer monitor device name
|
|
||||||
const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
|
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_rf_port_select = std::string("A_BALANCED");
|
||||||
const std::string default_gain_mode = std::string("slow_attack");
|
const std::string default_gain_mode = std::string("slow_attack");
|
||||||
const std::string empty_string;
|
|
||||||
const double default_tx_attenuation_db = -10.0;
|
const double default_tx_attenuation_db = -10.0;
|
||||||
const double default_manual_gain_rx1 = 64.0;
|
const double default_manual_gain_rx1 = 64.0;
|
||||||
const double default_manual_gain_rx2 = 64.0;
|
const double default_manual_gain_rx2 = 64.0;
|
||||||
@ -86,42 +80,27 @@ private:
|
|||||||
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
|
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
|
||||||
// sample block size when running in post-processing mode
|
// sample block size when running in post-processing mode
|
||||||
const int sample_block_size = 16384;
|
const int sample_block_size = 16384;
|
||||||
|
const int32_t switch_to_real_time_mode = 2;
|
||||||
void 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 run_dynamic_bit_selection_process();
|
void run_dynamic_bit_selection_process();
|
||||||
void run_buffer_monitor_process();
|
void run_buffer_monitor_process();
|
||||||
|
|
||||||
std::thread thread_file_to_dma;
|
|
||||||
std::thread thread_dynamic_bit_selection;
|
std::thread thread_dynamic_bit_selection;
|
||||||
std::thread thread_buffer_monitor;
|
std::thread thread_buffer_monitor;
|
||||||
|
|
||||||
std::shared_ptr<Fpga_Switch> switch_fpga;
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga;
|
std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga;
|
||||||
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
|
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
|
||||||
std::shared_ptr<Fpga_DMA> dma_fpga;
|
|
||||||
|
|
||||||
std::mutex dma_mutex;
|
|
||||||
std::mutex dynamic_bit_selection_mutex;
|
std::mutex dynamic_bit_selection_mutex;
|
||||||
std::mutex buffer_monitor_mutex;
|
std::mutex buffer_monitor_mutex;
|
||||||
|
|
||||||
Concurrent_Queue<pmt::pmt_t> *queue_;
|
|
||||||
|
|
||||||
std::string gain_mode_rx1_;
|
std::string gain_mode_rx1_;
|
||||||
std::string gain_mode_rx2_;
|
std::string gain_mode_rx2_;
|
||||||
std::string rf_port_select_;
|
std::string rf_port_select_;
|
||||||
std::string filter_file_;
|
std::string filter_file_;
|
||||||
std::string filter_source_;
|
std::string filter_source_;
|
||||||
std::string filter_filename_;
|
std::string filter_filename_;
|
||||||
std::string filename0_;
|
|
||||||
std::string filename1_;
|
|
||||||
|
|
||||||
double rf_gain_rx1_;
|
double rf_gain_rx1_;
|
||||||
double rf_gain_rx2_;
|
double rf_gain_rx2_;
|
||||||
@ -133,19 +112,14 @@ private:
|
|||||||
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present)
|
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present)
|
||||||
uint64_t sample_rate_;
|
uint64_t sample_rate_;
|
||||||
uint64_t bandwidth_;
|
uint64_t bandwidth_;
|
||||||
uint64_t samples_to_skip_;
|
|
||||||
int64_t samples_;
|
|
||||||
uint64_t freq_dds_tx_hz_;
|
uint64_t freq_dds_tx_hz_;
|
||||||
uint64_t freq_rf_tx_hz_;
|
uint64_t freq_rf_tx_hz_;
|
||||||
uint64_t tx_bandwidth_;
|
uint64_t tx_bandwidth_;
|
||||||
|
|
||||||
float Fpass_;
|
float Fpass_;
|
||||||
float Fstop_;
|
float Fstop_;
|
||||||
uint32_t num_input_files_;
|
|
||||||
uint32_t dma_buff_offset_pos_;
|
|
||||||
uint32_t in_stream_;
|
uint32_t in_stream_;
|
||||||
uint32_t out_stream_;
|
uint32_t out_stream_;
|
||||||
int32_t switch_position_;
|
|
||||||
|
|
||||||
size_t item_size_;
|
size_t item_size_;
|
||||||
|
|
||||||
@ -156,12 +130,10 @@ private:
|
|||||||
bool bb_dc_;
|
bool bb_dc_;
|
||||||
bool rx1_enable_;
|
bool rx1_enable_;
|
||||||
bool rx2_enable_;
|
bool rx2_enable_;
|
||||||
bool enable_DMA_;
|
|
||||||
bool enable_dynamic_bit_selection_;
|
bool enable_dynamic_bit_selection_;
|
||||||
bool enable_ovf_check_buffer_monitor_active_;
|
bool enable_ovf_check_buffer_monitor_active_;
|
||||||
bool dump_;
|
bool dump_;
|
||||||
bool rf_shutdown_;
|
bool rf_shutdown_;
|
||||||
bool repeat_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
585
src/algorithms/signal_source/adapters/dma_fpga_signal_source.cc
Normal file
585
src/algorithms/signal_source/adapters/dma_fpga_signal_source.cc
Normal file
@ -0,0 +1,585 @@
|
|||||||
|
/*!
|
||||||
|
* \file dma_fpga_signal_source.cc
|
||||||
|
* \brief signal source for a DMA connected directly to FPGA accelerators.
|
||||||
|
* This source implements only the DMA control. It is NOT compatible with
|
||||||
|
* conventional SDR acquisition and tracking blocks.
|
||||||
|
* \author Marc Majoral, mmajoral(at)cttc.es
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dma_fpga_signal_source.h"
|
||||||
|
#include "command_event.h"
|
||||||
|
#include "configuration_interface.h"
|
||||||
|
#include "gnss_sdr_flags.h"
|
||||||
|
#include "gnss_sdr_string_literals.h"
|
||||||
|
#include <chrono> // for std::chrono
|
||||||
|
#include <fcntl.h> // for open, O_WRONLY
|
||||||
|
#include <fstream> // for std::ifstream
|
||||||
|
#include <iomanip> // for std::setprecision
|
||||||
|
#include <iostream> // for std::cout
|
||||||
|
#include <vector> // fr std::vector
|
||||||
|
|
||||||
|
#if USE_GLOG_AND_GFLAGS
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/check.h>
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
DMAFpgaSignalSource::DMAFpgaSignalSource(const ConfigurationInterface *configuration,
|
||||||
|
const std::string &role, unsigned int in_stream, unsigned int out_stream,
|
||||||
|
Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused)))
|
||||||
|
: SignalSourceBase(configuration, role, "DMA_Fpga_Signal_Source"s),
|
||||||
|
queue_(queue),
|
||||||
|
filename0_(configuration->property(role + ".filename", empty_string)),
|
||||||
|
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
|
||||||
|
samples_to_skip_(0),
|
||||||
|
samples_(configuration->property(role + ".samples", static_cast<int64_t>(0))),
|
||||||
|
num_input_files_(1),
|
||||||
|
dma_buff_offset_pos_(0),
|
||||||
|
in_stream_(in_stream),
|
||||||
|
out_stream_(out_stream),
|
||||||
|
item_size_(sizeof(int8_t)),
|
||||||
|
enable_DMA_(false),
|
||||||
|
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 != "-")
|
||||||
|
{
|
||||||
|
filename0_ = FLAGS_signal_source;
|
||||||
|
}
|
||||||
|
if (FLAGS_s != "-")
|
||||||
|
{
|
||||||
|
filename0_ = FLAGS_s;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (absl::GetFlag(FLAGS_signal_source) != "-")
|
||||||
|
{
|
||||||
|
filename0_ = absl::GetFlag(FLAGS_signal_source);
|
||||||
|
}
|
||||||
|
if (absl::GetFlag(FLAGS_s) != "-")
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seconds_to_skip > 0)
|
||||||
|
{
|
||||||
|
samples_to_skip_ = static_cast<uint64_t>(seconds_to_skip * sample_rate_) * 2;
|
||||||
|
}
|
||||||
|
if (header_size > 0)
|
||||||
|
{
|
||||||
|
samples_to_skip_ += header_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
|
switch_fpga->set_switch_position(switch_to_DMA);
|
||||||
|
|
||||||
|
enable_DMA_ = true;
|
||||||
|
|
||||||
|
if (samples_ == 0) // read all file
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File.
|
||||||
|
* A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the
|
||||||
|
* valve block
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
if (filename1_.empty())
|
||||||
|
{
|
||||||
|
DLOG(INFO) << "File source filename " << filename0_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DLOG(INFO) << "File source filename rx1 " << filename0_;
|
||||||
|
DLOG(INFO) << "File source filename rx2 " << filename1_;
|
||||||
|
}
|
||||||
|
DLOG(INFO) << "Samples " << samples_;
|
||||||
|
DLOG(INFO) << "Sampling frequency " << sample_rate_;
|
||||||
|
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);
|
||||||
|
thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stream_ > 0)
|
||||||
|
{
|
||||||
|
LOG(ERROR) << "A signal source does not have an input stream";
|
||||||
|
}
|
||||||
|
if (out_stream_ > 1)
|
||||||
|
{
|
||||||
|
LOG(ERROR) << "This implementation only supports one output stream";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DMAFpgaSignalSource::~DMAFpgaSignalSource()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock_DMA(dma_mutex);
|
||||||
|
enable_DMA_ = false; // disable the DMA
|
||||||
|
lock_DMA.unlock();
|
||||||
|
if (thread_file_to_dma.joinable())
|
||||||
|
{
|
||||||
|
thread_file_to_dma.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
|
||||||
|
bool bit_selection_enabled = enable_dynamic_bit_selection_;
|
||||||
|
lock_dyn_bit_sel.unlock();
|
||||||
|
|
||||||
|
if (bit_selection_enabled == true)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex);
|
||||||
|
enable_dynamic_bit_selection_ = false;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if (thread_dynamic_bit_selection.joinable())
|
||||||
|
{
|
||||||
|
thread_dynamic_bit_selection.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMAFpgaSignalSource::start()
|
||||||
|
{
|
||||||
|
thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMAFpgaSignalSource::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)
|
||||||
|
{
|
||||||
|
std::ifstream infile1;
|
||||||
|
infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
|
||||||
|
|
||||||
|
// FPGA DMA control
|
||||||
|
dma_fpga = std::make_shared<Fpga_DMA>();
|
||||||
|
|
||||||
|
// open the files
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.open(filename0_, std::ios::binary);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception opening file " << filename0_ << '\n';
|
||||||
|
// stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream infile2;
|
||||||
|
if (!filename1_.empty())
|
||||||
|
{
|
||||||
|
infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.open(filename1_, std::ios::binary);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception opening file " << filename1_ << '\n';
|
||||||
|
// stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip the initial samples if needed
|
||||||
|
uint64_t bytes_to_skeep = samples_to_skip * item_size;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.ignore(bytes_to_skeep);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception skipping initial samples file " << filename0_ << '\n';
|
||||||
|
// stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename1_.empty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.ignore(bytes_to_skeep);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception skipping initial samples file " << filename1_ << '\n';
|
||||||
|
// stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rx signal vectors
|
||||||
|
std::vector<int8_t> input_samples(sample_block_size * 2); // complex samples
|
||||||
|
// pointer to DMA buffer
|
||||||
|
int8_t *dma_buffer;
|
||||||
|
int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1
|
||||||
|
bool run_DMA = true;
|
||||||
|
|
||||||
|
// Open DMA device
|
||||||
|
if (dma_fpga->DMA_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Cannot open loop device\n";
|
||||||
|
// stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dma_buffer = dma_fpga->get_buffer_address();
|
||||||
|
|
||||||
|
// if only one frequency band is used then clear the samples corresponding to the unused frequency band
|
||||||
|
uint32_t dma_index = 0;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0;
|
||||||
|
dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0;
|
||||||
|
dma_index += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t nbytes_remaining = samples * item_size;
|
||||||
|
uint32_t read_buffer_size = sample_block_size * 2; // complex samples
|
||||||
|
|
||||||
|
// run the DMA
|
||||||
|
while (run_DMA)
|
||||||
|
{
|
||||||
|
dma_index = 0;
|
||||||
|
if (nbytes_remaining < read_buffer_size)
|
||||||
|
{
|
||||||
|
read_buffer_size = nbytes_remaining;
|
||||||
|
}
|
||||||
|
nbytes_remaining = nbytes_remaining - read_buffer_size;
|
||||||
|
|
||||||
|
// read filename 0
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception reading file " << filename0_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (infile1)
|
||||||
|
{
|
||||||
|
nread_elements = read_buffer_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FLAG AS ERROR !! IT SHOULD NEVER HAPPEN
|
||||||
|
nread_elements = infile1.gcount();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index0 = 0; index0 < (nread_elements); index0 += 2)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read filename 1 (if enabled)
|
||||||
|
if (num_input_files_ > 1)
|
||||||
|
{
|
||||||
|
dma_index = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception reading file " << filename1_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (infile2)
|
||||||
|
{
|
||||||
|
nread_elements = read_buffer_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FLAG AS ERROR !! IT SHOULD NEVER HAPPEN
|
||||||
|
nread_elements = infile2.gcount();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index0 = 0; index0 < (nread_elements); index0 += 2)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nread_elements > 0)
|
||||||
|
{
|
||||||
|
if (dma_fpga->DMA_write(nread_elements * 2))
|
||||||
|
{
|
||||||
|
std::cerr << "Error: DMA could not send all the required samples\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Throttle the DMA
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes_remaining == 0)
|
||||||
|
{
|
||||||
|
if (repeat)
|
||||||
|
{
|
||||||
|
// read the file again
|
||||||
|
nbytes_remaining = samples * item_size;
|
||||||
|
read_buffer_size = sample_block_size * 2;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.seekg(0);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip the initial samples if needed
|
||||||
|
uint64_t bytes_to_skeep = samples_to_skip * item_size;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.ignore(bytes_to_skeep);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception skipping initial samples file " << filename0_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename1_.empty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.seekg(0);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.ignore(bytes_to_skeep);
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception skipping initial samples file " << filename1_ << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the input file is completely processed. Stop the receiver.
|
||||||
|
run_DMA = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::unique_lock<std::mutex> lock_DMA(dma_mutex);
|
||||||
|
if (enable_DMA_ == false)
|
||||||
|
{
|
||||||
|
run_DMA = false;
|
||||||
|
}
|
||||||
|
lock_DMA.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dma_fpga->DMA_close())
|
||||||
|
{
|
||||||
|
std::cerr << "Error closing loop device " << '\n';
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile1.close();
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception closing file " << filename0_ << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_input_files_ > 1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
infile2.close();
|
||||||
|
}
|
||||||
|
catch (const std::ifstream::failure &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception closing file " << filename1_ << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the receiver
|
||||||
|
queue->push(pmt::make_any(command_event_make(200, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMAFpgaSignalSource::run_dynamic_bit_selection_process()
|
||||||
|
{
|
||||||
|
bool dynamic_bit_selection_active = true;
|
||||||
|
|
||||||
|
while (dynamic_bit_selection_active)
|
||||||
|
{
|
||||||
|
// 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::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
|
||||||
|
if (enable_dynamic_bit_selection_ == false)
|
||||||
|
{
|
||||||
|
dynamic_bit_selection_active = false;
|
||||||
|
}
|
||||||
|
lock_dyn_bit_sel.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMAFpgaSignalSource::connect(gr::top_block_sptr top_block)
|
||||||
|
{
|
||||||
|
if (top_block)
|
||||||
|
{ /* top_block is not null */
|
||||||
|
};
|
||||||
|
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMAFpgaSignalSource::disconnect(gr::top_block_sptr top_block)
|
||||||
|
{
|
||||||
|
if (top_block)
|
||||||
|
{ /* top_block is not null */
|
||||||
|
};
|
||||||
|
DLOG(INFO) << "AD9361 FPGA source nothing to disconnect";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gr::basic_block_sptr DMAFpgaSignalSource::get_left_block()
|
||||||
|
{
|
||||||
|
LOG(WARNING) << "Trying to get signal source left block.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gr::basic_block_sptr DMAFpgaSignalSource::get_right_block()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
118
src/algorithms/signal_source/adapters/dma_fpga_signal_source.h
Normal file
118
src/algorithms/signal_source/adapters/dma_fpga_signal_source.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*!
|
||||||
|
* \file dma_fpga_signal_source.h
|
||||||
|
* \brief signal source for a DMA connected directly to FPGA accelerators.
|
||||||
|
* This source implements only the DMA control. It is NOT compatible with
|
||||||
|
* conventional SDR acquisition and tracking blocks.
|
||||||
|
* \author Marc Majoral, mmajoral(at)cttc.es
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GNSS_SDR_DMA_FPGA_SIGNAL_SOURCE_H
|
||||||
|
#define GNSS_SDR_DMA_FPGA_SIGNAL_SOURCE_H
|
||||||
|
|
||||||
|
#include "concurrent_queue.h"
|
||||||
|
#include "fpga_dma-proxy.h"
|
||||||
|
#include "fpga_dynamic_bit_selection.h"
|
||||||
|
#include "fpga_switch.h"
|
||||||
|
#include "gnss_block_interface.h"
|
||||||
|
#include "signal_source_base.h"
|
||||||
|
#include <pmt/pmt.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
/** \addtogroup Signal_Source
|
||||||
|
* \{ */
|
||||||
|
/** \addtogroup Signal_Source_adapters
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationInterface;
|
||||||
|
|
||||||
|
class DMAFpgaSignalSource : public SignalSourceBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DMAFpgaSignalSource(const ConfigurationInterface *configuration,
|
||||||
|
const std::string &role, unsigned int in_stream,
|
||||||
|
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
|
||||||
|
|
||||||
|
~DMAFpgaSignalSource();
|
||||||
|
|
||||||
|
void start() override;
|
||||||
|
|
||||||
|
inline size_t item_size() override
|
||||||
|
{
|
||||||
|
return item_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(gr::top_block_sptr top_block) override;
|
||||||
|
void disconnect(gr::top_block_sptr top_block) override;
|
||||||
|
gr::basic_block_sptr get_left_block() override;
|
||||||
|
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;
|
||||||
|
|
||||||
|
void 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 run_dynamic_bit_selection_process();
|
||||||
|
|
||||||
|
std::thread thread_file_to_dma;
|
||||||
|
std::thread thread_dynamic_bit_selection;
|
||||||
|
|
||||||
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
|
std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga;
|
||||||
|
std::shared_ptr<Fpga_DMA> dma_fpga;
|
||||||
|
|
||||||
|
std::mutex dma_mutex;
|
||||||
|
std::mutex dynamic_bit_selection_mutex;
|
||||||
|
|
||||||
|
Concurrent_Queue<pmt::pmt_t> *queue_;
|
||||||
|
|
||||||
|
std::string filename0_;
|
||||||
|
std::string filename1_;
|
||||||
|
|
||||||
|
uint64_t sample_rate_;
|
||||||
|
uint64_t samples_to_skip_;
|
||||||
|
int64_t samples_;
|
||||||
|
uint32_t num_input_files_;
|
||||||
|
uint32_t dma_buff_offset_pos_;
|
||||||
|
uint32_t in_stream_;
|
||||||
|
uint32_t out_stream_;
|
||||||
|
size_t item_size_;
|
||||||
|
|
||||||
|
bool enable_DMA_;
|
||||||
|
bool enable_dynamic_bit_selection_;
|
||||||
|
bool repeat_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
/** \} */
|
||||||
|
#endif // GNSS_SDR_DMA_FPGA_SIGNAL_SOURCE_H
|
@ -25,6 +25,7 @@
|
|||||||
#include "fpga_buffer_monitor.h"
|
#include "fpga_buffer_monitor.h"
|
||||||
#include "gnss_sdr_create_directory.h"
|
#include "gnss_sdr_create_directory.h"
|
||||||
#include "gnss_sdr_filesystem.h"
|
#include "gnss_sdr_filesystem.h"
|
||||||
|
#include "uio_fpga.h"
|
||||||
#include <ctime> // for time, localtime
|
#include <ctime> // for time, localtime
|
||||||
#include <fcntl.h> // for open, O_RDWR, O_SYNC
|
#include <fcntl.h> // for open, O_RDWR, O_SYNC
|
||||||
#include <fstream> // for string, ofstream
|
#include <fstream> // for string, ofstream
|
||||||
@ -40,7 +41,16 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
|
//Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
|
||||||
|
// uint32_t num_freq_bands,
|
||||||
|
// bool dump,
|
||||||
|
// std::string dump_filename)
|
||||||
|
// : d_dump_filename(std::move(dump_filename)),
|
||||||
|
// d_num_freq_bands(num_freq_bands),
|
||||||
|
// d_max_buff_occ_freq_band_0(0),
|
||||||
|
// d_max_buff_occ_freq_band_1(0),
|
||||||
|
// d_dump(dump)
|
||||||
|
Fpga_buffer_monitor::Fpga_buffer_monitor(
|
||||||
uint32_t num_freq_bands,
|
uint32_t num_freq_bands,
|
||||||
bool dump,
|
bool dump,
|
||||||
std::string dump_filename)
|
std::string dump_filename)
|
||||||
@ -50,10 +60,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
|
|||||||
d_max_buff_occ_freq_band_1(0),
|
d_max_buff_occ_freq_band_1(0),
|
||||||
d_dump(dump)
|
d_dump(dump)
|
||||||
{
|
{
|
||||||
// open device descriptor
|
std::string device_io_name;
|
||||||
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
|
||||||
|
// find the uio device file corresponding to the buffer monitor
|
||||||
|
if (find_uio_dev_file_name(device_io_name, BUFFER_MONITOR_DEVICE_NAME, 0) < 0)
|
||||||
{
|
{
|
||||||
LOG(WARNING) << "Cannot open deviceio" << device_name;
|
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << BUFFER_MONITOR_DEVICE_NAME << '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open device descriptor
|
||||||
|
if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
||||||
|
{
|
||||||
|
LOG(WARNING) << "Cannot open deviceio" << device_io_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// device memory map
|
// device memory map
|
||||||
|
@ -45,10 +45,13 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
* \brief Constructor
|
* \brief Constructor
|
||||||
*/
|
*/
|
||||||
explicit Fpga_buffer_monitor(const std::string& device_name,
|
explicit Fpga_buffer_monitor(uint32_t num_freq_bands,
|
||||||
uint32_t num_freq_bands,
|
|
||||||
bool dump,
|
bool dump,
|
||||||
std::string dump_filename);
|
std::string dump_filename);
|
||||||
|
// explicit Fpga_buffer_monitor(const std::string& device_name,
|
||||||
|
// uint32_t num_freq_bands,
|
||||||
|
// bool dump,
|
||||||
|
// std::string dump_filename);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destructor
|
* \brief Destructor
|
||||||
@ -61,6 +64,7 @@ public:
|
|||||||
void check_buffer_overflow_and_monitor_buffer_status();
|
void check_buffer_overflow_and_monitor_buffer_status();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const std::string BUFFER_MONITOR_DEVICE_NAME = std::string("buffer_monitor"); // buffer monitor device name
|
||||||
static const size_t FPGA_PAGE_SIZE = 0x1000;
|
static const size_t FPGA_PAGE_SIZE = 0x1000;
|
||||||
static const uint32_t test_register_writeval = 0x55AA;
|
static const uint32_t test_register_writeval = 0x55AA;
|
||||||
static const uint32_t num_sapmples_per_buffer_element = 2;
|
static const uint32_t num_sapmples_per_buffer_element = 2;
|
||||||
|
@ -56,7 +56,6 @@ public:
|
|||||||
void bit_selection(void);
|
void bit_selection(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
|
|
||||||
const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
|
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 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_ADC = 12; // Number of bits in the ADC
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fpga_switch.h"
|
#include "fpga_switch.h"
|
||||||
|
#include "uio_fpga.h"
|
||||||
#include <fcntl.h> // for open, O_RDWR, O_SYNC
|
#include <fcntl.h> // for open, O_RDWR, O_SYNC
|
||||||
#include <iostream> // for cout
|
#include <iostream> // for cout
|
||||||
#include <sys/mman.h> // for mmap
|
#include <sys/mman.h> // for mmap
|
||||||
@ -32,11 +33,19 @@
|
|||||||
#include <absl/log/log.h>
|
#include <absl/log/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Fpga_Switch::Fpga_Switch(const std::string &device_name)
|
Fpga_Switch::Fpga_Switch(void)
|
||||||
{
|
{
|
||||||
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
std::string device_io_name; // Switch UIO device file
|
||||||
|
// find the uio device file corresponding to the switch.
|
||||||
|
if (find_uio_dev_file_name(device_io_name, SWITCH_DEVICE_NAME, 0) < 0)
|
||||||
{
|
{
|
||||||
LOG(WARNING) << "Cannot open deviceio" << device_name;
|
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << SWITCH_DEVICE_NAME << '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
||||||
|
{
|
||||||
|
LOG(WARNING) << "Cannot open deviceio" << device_io_name;
|
||||||
}
|
}
|
||||||
d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
|
d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));
|
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));
|
||||||
|
@ -42,8 +42,7 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
* \brief Constructor
|
* \brief Constructor
|
||||||
*/
|
*/
|
||||||
explicit Fpga_Switch(const std::string& device_name);
|
explicit Fpga_Switch(void);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destructor
|
* \brief Destructor
|
||||||
*/
|
*/
|
||||||
@ -55,6 +54,7 @@ public:
|
|||||||
void set_switch_position(int32_t switch_position);
|
void set_switch_position(int32_t switch_position);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const std::string SWITCH_DEVICE_NAME = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
|
||||||
static const size_t FPGA_PAGE_SIZE = 0x1000;
|
static const size_t FPGA_PAGE_SIZE = 0x1000;
|
||||||
static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA;
|
static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA;
|
||||||
static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50;
|
static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50;
|
||||||
|
@ -128,6 +128,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_FPGA
|
#if ENABLE_FPGA
|
||||||
|
#include "dma_fpga_signal_source.h"
|
||||||
#include "galileo_e1_dll_pll_veml_tracking_fpga.h"
|
#include "galileo_e1_dll_pll_veml_tracking_fpga.h"
|
||||||
#include "galileo_e1_pcps_ambiguous_acquisition_fpga.h"
|
#include "galileo_e1_pcps_ambiguous_acquisition_fpga.h"
|
||||||
#include "galileo_e5a_dll_pll_tracking_fpga.h"
|
#include "galileo_e5a_dll_pll_tracking_fpga.h"
|
||||||
@ -811,7 +812,7 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if AD9361_DRIVER
|
#if ENABLE_FPGA and AD9361_DRIVER
|
||||||
// The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver
|
// The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver
|
||||||
// in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver.
|
// in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver.
|
||||||
else if (implementation == "Ad9361_Fpga_Signal_Source")
|
else if (implementation == "Ad9361_Fpga_Signal_Source")
|
||||||
@ -822,6 +823,15 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_FPGA
|
||||||
|
else if (implementation == "DMA_Fpga_Signal_Source")
|
||||||
|
{
|
||||||
|
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<DMAFpgaSignalSource>(configuration, role, in_streams,
|
||||||
|
out_streams, queue);
|
||||||
|
block = std::move(block_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ZEROMQ_DRIVER
|
#if ZEROMQ_DRIVER
|
||||||
else if (implementation == "ZMQ_Signal_Source")
|
else if (implementation == "ZMQ_Signal_Source")
|
||||||
{
|
{
|
||||||
|
@ -547,7 +547,7 @@ int GNSSFlowgraph::connect_fpga_flowgraph()
|
|||||||
if (src == nullptr)
|
if (src == nullptr)
|
||||||
{
|
{
|
||||||
help_hint_ += " * Check implementation name for SignalSource block.\n";
|
help_hint_ += " * Check implementation name for SignalSource block.\n";
|
||||||
help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source\n";
|
help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source or DMA_Fpga_Signal_Source\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (src->item_size() == 0)
|
if (src->item_size() == 0)
|
||||||
|
@ -321,7 +321,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal()
|
|||||||
// instantiate the FPGA switch and set the
|
// instantiate the FPGA switch and set the
|
||||||
// switch position to DMA.
|
// switch position to DMA.
|
||||||
std::shared_ptr<Fpga_Switch> switch_fpga;
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1");
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
switch_fpga->set_switch_position(0); // set switch position to DMA
|
switch_fpga->set_switch_position(0); // set switch position to DMA
|
||||||
|
|
||||||
// create the correspondign acquisition block according to the desired tracking signal
|
// create the correspondign acquisition block according to the desired tracking signal
|
||||||
|
@ -320,7 +320,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal()
|
|||||||
// instantiate the FPGA switch and set the
|
// instantiate the FPGA switch and set the
|
||||||
// switch position to DMA.
|
// switch position to DMA.
|
||||||
std::shared_ptr<Fpga_Switch> switch_fpga;
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1");
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
switch_fpga->set_switch_position(0); // set switch position to DMA
|
switch_fpga->set_switch_position(0); // set switch position to DMA
|
||||||
|
|
||||||
// create the correspondign acquisition block according to the desired tracking signal
|
// create the correspondign acquisition block according to the desired tracking signal
|
||||||
|
@ -638,7 +638,7 @@ bool HybridObservablesTestFpga::acquire_signal()
|
|||||||
// instantiate the FPGA switch and set the
|
// instantiate the FPGA switch and set the
|
||||||
// switch position to DMA.
|
// switch position to DMA.
|
||||||
std::shared_ptr<Fpga_Switch> switch_fpga;
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1");
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
switch_fpga->set_switch_position(0); // set switch position to DMA
|
switch_fpga->set_switch_position(0); // set switch position to DMA
|
||||||
|
|
||||||
// create the correspondign acquisition block according to the desired tracking signal
|
// create the correspondign acquisition block according to the desired tracking signal
|
||||||
|
@ -634,7 +634,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
|
|||||||
// instantiate the FPGA switch and set the
|
// instantiate the FPGA switch and set the
|
||||||
// switch position to DMA.
|
// switch position to DMA.
|
||||||
std::shared_ptr<Fpga_Switch> switch_fpga;
|
std::shared_ptr<Fpga_Switch> switch_fpga;
|
||||||
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1");
|
switch_fpga = std::make_shared<Fpga_Switch>();
|
||||||
switch_fpga->set_switch_position(0); // set switch position to DMA
|
switch_fpga->set_switch_position(0); // set switch position to DMA
|
||||||
|
|
||||||
// create the correspondign acquisition block according to the desired tracking signal
|
// create the correspondign acquisition block according to the desired tracking signal
|
||||||
|
Loading…
Reference in New Issue
Block a user