1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-12-19 14:58:06 +00:00

Release 0.0.20

This commit is contained in:
Carles Fernandez
2025-04-01 15:34:18 +02:00
795 changed files with 25647 additions and 6395 deletions

View File

@@ -25,6 +25,14 @@ if(ENABLE_PLUTOSDR)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h)
endif()
if(ENABLE_AD936X_SDR AND NOT ENABLE_PLUTOSDR)
##############################################
# CUSTOM AD936X IIO SOURCE
##############################################
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_custom_signal_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h)
endif()
if(ENABLE_FMCOMMS2)
###############################################
# FMCOMMS2 based SDR Hardware
@@ -37,8 +45,26 @@ if(ENABLE_AD9361)
###############################################
# AD9361 DIRECT TO FPGA Hardware
###############################################
list(APPEND OPT_DRIVER_SOURCES ad9361_fpga_signal_source.cc)
list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h)
list(APPEND OPT_DRIVER_SOURCES adrv9361_z7035_signal_source_fpga.cc)
list(APPEND OPT_DRIVER_HEADERS adrv9361_z7035_signal_source_fpga.h)
list(APPEND OPT_DRIVER_SOURCES fmcomms5_signal_source_fpga.cc)
list(APPEND OPT_DRIVER_HEADERS fmcomms5_signal_source_fpga.h)
endif()
if(ENABLE_MAX2771)
###############################################
# MAX2771 EVKIT DIRECT TO FPGA Hardware
###############################################
list(APPEND OPT_DRIVER_SOURCES max2771_evkit_signal_source_fpga.cc)
list(APPEND OPT_DRIVER_HEADERS max2771_evkit_signal_source_fpga.h)
endif()
if(ENABLE_DMA_PROXY)
###############################################
# FPGA DMA source
###############################################
list(APPEND OPT_DRIVER_SOURCES dma_signal_source_fpga.cc)
list(APPEND OPT_DRIVER_HEADERS dma_signal_source_fpga.h)
endif()
if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND)
@@ -85,6 +111,11 @@ if(ENABLE_ZMQ)
list(APPEND OPT_DRIVER_HEADERS zmq_signal_source.h)
endif()
if(ENABLE_ION)
list(APPEND OPT_DRIVER_SOURCES ion_gsms_signal_source.cc)
list(APPEND OPT_DRIVER_HEADERS ion_gsms_signal_source.h)
endif()
set(SIGNAL_SOURCE_ADAPTER_SOURCES
signal_source_base.cc
file_source_base.cc
@@ -151,7 +182,7 @@ target_include_directories(signal_source_adapters
${GNSSSDR_SOURCE_DIR}/src/core/interfaces
)
if(ENABLE_FPGA OR ENABLE_AD9361)
if(ENABLE_FPGA OR ENABLE_AD9361 OR ENABLE_ION)
target_link_libraries(signal_source_adapters
PUBLIC
signal_source_libs
@@ -169,10 +200,16 @@ target_link_libraries(signal_source_adapters
algorithms_libs
gnss_sdr_flags
core_system_parameters
Glog::glog
Volk::volk
)
if(ENABLE_GLOG_AND_GFLAGS)
target_link_libraries(signal_source_adapters PRIVATE Glog::glog)
target_compile_definitions(signal_source_adapters PRIVATE -DUSE_GLOG_AND_GFLAGS=1)
else()
target_link_libraries(signal_source_adapters PRIVATE absl::flags absl::log)
endif()
if(GNURADIO_USES_STD_POINTERS)
target_compile_definitions(signal_source_adapters
PUBLIC -DGNURADIO_USES_STD_POINTERS=1
@@ -215,14 +252,14 @@ if(ENABLE_LIMESDR AND GRLIMESDR_FOUND)
)
endif()
if(ENABLE_AD9361 AND LIBIIO_FOUND)
if(LIBIIO_FOUND)
target_link_libraries(signal_source_adapters
PRIVATE
Iio::iio
)
endif()
if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR)
if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR)
if(LIBAD9361_VERSION)
if(LIBAD9361_VERSION VERSION_GREATER 0.1)
target_compile_definitions(signal_source_adapters

View File

@@ -1,867 +0,0 @@
/*!
* \file ad9361_fpga_signal_source.cc
* \brief signal source for Analog Devices front-end AD9361 connected directly
* to FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
* is selected in the configuration file.
* \authors <ul>
* <li> Javier Arribas, jarribas(at)cttc.es
* <li> Marc Majoral, mmajoral(at)cttc.es
* </ul>
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad9361_fpga_signal_source.h"
#include "GPS_L1_CA.h"
#include "GPS_L5.h"
#include "ad9361_manager.h"
#include "command_event.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "uio_fpga.h"
#include <glog/logging.h>
#include <iio.h>
#include <algorithm> // for std::max
#include <chrono> // for std::chrono
#include <cmath> // for std::floor
#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 <unistd.h> // for write
#include <vector> // fr std::vector
using namespace std::string_literals;
Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(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, "Ad9361_Fpga_Signal_Source"s),
queue_(queue),
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)),
gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)),
rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)),
filter_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_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)),
scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)),
phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)),
tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)),
freq0_(configuration->property(role + ".freq", 0)),
freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))),
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
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_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))),
Fpass_(configuration->property(role + ".Fpass", 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),
out_stream_(out_stream),
switch_position_(configuration->property(role + ".switch_position", 0)),
item_size_(sizeof(int8_t)),
enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)),
filter_auto_(configuration->property(role + ".filter_auto", false)),
quadrature_(configuration->property(role + ".quadrature", true)),
rf_dc_(configuration->property(role + ".rf_dc", true)),
bb_dc_(configuration->property(role + ".bb_dc", true)),
rx1_enable_(configuration->property(role + ".rx1_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_ovf_check_buffer_monitor_active_(false),
dump_(configuration->property(role + ".dump", false)),
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)),
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));
const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1;
if (freq0_ == 0)
{
// use ".freq0"
freq0_ = configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ));
}
if (filter_auto_)
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Auto"));
}
else
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Off"));
}
// override value with commandline flag, if present
if (FLAGS_signal_source != "-")
{
filename0_ = FLAGS_signal_source;
}
if (FLAGS_s != "-")
{
filename0_ = FLAGS_s;
}
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;
}
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)
{
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << '\n';
return;
}
if (switch_position_ != 0 && switch_position_ != 2)
{
std::cout << "SignalSource.switch_position configuration parameter must be either 0: read from file(s) via DMA, or 2: read from AD9361\n";
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
{
/*!
* 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_;
}
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
{
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;
}
// 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(); });
}
// 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";
}
}
Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource()
{
/* cleanup and exit */
if (switch_position_ == 0) // read samples from a file via DMA
{
std::unique_lock<std::mutex> lock(dma_mutex);
enable_DMA_ = false; // disable the DMA
lock.unlock();
if (thread_file_to_dma.joinable())
{
thread_file_to_dma.join();
}
}
if (switch_position_ == 2) // Real-time via AD9361
{
if (rf_shutdown_)
{
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);
bool bit_selection_enabled = enable_dynamic_bit_selection_;
lock.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 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()
{
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(dynamic_bit_selection_mutex);
if (enable_dynamic_bit_selection_ == false)
{
dynamic_bit_selection_active = false;
}
lock.unlock();
}
}
void Ad9361FpgaSignalSource::run_buffer_monitor_process()
{
bool enable_ovf_check_buffer_monitor_active = true;
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms));
while (enable_ovf_check_buffer_monitor_active)
{
buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status();
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms));
std::unique_lock<std::mutex> lock(buffer_monitor_mutex);
if (enable_ovf_check_buffer_monitor_active_ == false)
{
enable_ovf_check_buffer_monitor_active = false;
}
lock.unlock();
}
}
void Ad9361FpgaSignalSource::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void Ad9361FpgaSignalSource::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 Ad9361FpgaSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr Ad9361FpgaSignalSource::get_right_block()
{
return {};
}

View File

@@ -21,10 +21,15 @@
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* configuration,
@@ -71,8 +76,11 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface*
item_size_ = sizeof(gr_complex);
// 1. Make the driver instance
bool customsamplesize = false;
if (ssize_ != 12 or spattern_ == true) customsamplesize = true; // custom FPGA DMA firmware
if (ssize_ == 12) // default original FPGA DMA firmware
if (ssize_ != 12 || spattern_ == true)
{
customsamplesize = true; // custom FPGA DMA firmware
}
if (ssize_ == 12) // default original FPGA DMA firmware
{
ssize_ = 16; // set to 16 bits and do not try to change sample size
}
@@ -148,8 +156,14 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface*
for (int n = 0; n < n_channels; n++)
{
if (n == 0) inverted_spectrum_vec.push_back(inverted_spectrum_ch0_);
if (n == 1) inverted_spectrum_vec.push_back(inverted_spectrum_ch1_);
if (n == 0)
{
inverted_spectrum_vec.push_back(inverted_spectrum_ch0_);
}
if (n == 1)
{
inverted_spectrum_vec.push_back(inverted_spectrum_ch1_);
}
}
for (int n = 0; n < n_channels; n++)

View File

@@ -0,0 +1,399 @@
/*!
* \file adrv9361_z7035_signal_source_fpga.cc
* \brief Signal source for the Analog Devices ADRV9361-Z7035 evaluation board
* directly connected to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
* is selected in the configuration file.
* \authors <ul>
* <li> Javier Arribas, jarribas(at)cttc.es
* <li> Marc Majoral, mmajoral(at)cttc.es
* </ul>
*
* -----------------------------------------------------------------------------
*
* 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 "adrv9361_z7035_signal_source_fpga.h"
#include "GPS_L1_CA.h"
#include "GPS_L5.h"
#include "ad9361_manager.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <algorithm> // for std::max
#include <chrono> // for std::chrono
#include <cmath> // for std::floor
#include <exception> // for std::exception
#include <iostream> // for std::cout
#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;
Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(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, "ADRV9361_Z7035_Signal_Source_FPGA"s),
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)),
gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)),
rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)),
filter_source_(configuration->property(role + ".filter_source", std::string("Off"))),
filter_filename_(configuration->property(role + ".filter_filename", filter_file_)),
rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)),
rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)),
scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)),
phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)),
tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)),
freq0_(configuration->property(role + ".freq", GPS_L5_FREQ_HZ)),
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))),
freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast<uint64_t>(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))),
tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(500000))),
Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))),
Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))),
in_stream_(in_stream),
out_stream_(out_stream),
item_size_(sizeof(int8_t)),
enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)),
quadrature_(configuration->property(role + ".quadrature", true)),
rf_dc_(configuration->property(role + ".rf_dc", true)),
bb_dc_(configuration->property(role + ".bb_dc", true)),
rx1_enable_(configuration->property(role + ".rx1_enable", true)),
rx2_enable_(configuration->property(role + ".rx2_enable", true)),
enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)),
enable_ovf_check_buffer_monitor_active_(true),
dump_(configuration->property(role + ".dump", false)),
#if USE_GLOG_AND_GFLAGS
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown))
#else
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown)))
#endif
{
const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) ||
(configuration->property("Channels_1B.count", 0) > 0));
const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) ||
(configuration->property("Channels_L5.count", 0) > 0) ||
(configuration->property("Channels_5X.count", 0) > 0));
const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1;
if (freq0_ == 0)
{
// use ".freq0"
freq0_ = configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ));
}
switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(switch_to_real_time_mode);
std::cout << "Sample rate: " << sample_rate_ << " Sps\n";
// some basic checks
if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2"))
{
std::cout << "Configuration parameter rf_port_select should take one of these values:\n";
std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n";
std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n';
rf_port_select_ = default_rf_port_select;
LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select;
}
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";
uint64_t freq1 = 0; // The local oscillator frequency of the ADRV9361-B is not used when using the ADRV9361-Z7035 board.
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;
}
// 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;
}
}
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
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";
}
}
Adrv9361z7035SignalSourceFPGA::~Adrv9361z7035SignalSourceFPGA()
{
// cleanup and exit
if (rf_shutdown_)
{
std::cout << "* AD9361 Disabling RX streaming channels\n";
try
{
if (!disable_ad9361_rx_local())
{
LOG(WARNING) << "Problem shutting down the AD9361 RX channels";
}
}
catch (const std::exception &e)
{
LOG(WARNING) << "Problem shutting down the AD9361 RX channels: " << e.what();
std::cerr << "Problem shutting down the AD9361 RX channels: " << e.what() << '\n';
}
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::lock_guard<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
}
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.join();
}
bool bit_selection_enabled = false;
{
std::lock_guard<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
bit_selection_enabled = enable_dynamic_bit_selection_;
}
if (bit_selection_enabled == true)
{
{
std::lock_guard<std::mutex> lock(dynamic_bit_selection_mutex);
enable_dynamic_bit_selection_ = false;
}
if (thread_dynamic_bit_selection.joinable())
{
thread_dynamic_bit_selection.join();
}
}
}
void Adrv9361z7035SignalSourceFPGA::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::lock_guard<std::mutex> lock(dynamic_bit_selection_mutex);
if (enable_dynamic_bit_selection_ == false)
{
dynamic_bit_selection_active = false;
}
}
}
void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process()
{
bool enable_ovf_check_buffer_monitor_active = true;
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms));
while (enable_ovf_check_buffer_monitor_active)
{
buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status();
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms));
std::lock_guard<std::mutex> lock(buffer_monitor_mutex);
if (enable_ovf_check_buffer_monitor_active_ == false)
{
enable_ovf_check_buffer_monitor_active = false;
}
}
}
void Adrv9361z7035SignalSourceFPGA::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void Adrv9361z7035SignalSourceFPGA::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 Adrv9361z7035SignalSourceFPGA::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr Adrv9361z7035SignalSourceFPGA::get_right_block()
{
return {};
}

View File

@@ -1,7 +1,7 @@
/*!
* \file ad9361_fpga_signal_source.h
* \brief signal source for Analog Devices front-end AD9361 connected directly
* to FPGA accelerators.
* \file adrv9361_z7035_signal_source_fpga.h
* \brief Signal source for the Analog Devices ADRV9361-Z7035 evaluation board
* directly connected to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
@@ -12,18 +12,17 @@
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
#ifndef GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
#define GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
#include "concurrent_queue.h"
#include "fpga_buffer_monitor.h"
#include "fpga_dma-proxy.h"
#include "fpga_dynamic_bit_selection.h"
#include "fpga_switch.h"
#include "gnss_block_interface.h"
@@ -44,16 +43,14 @@
class ConfigurationInterface;
class Ad9361FpgaSignalSource : public SignalSourceBase
class Adrv9361z7035SignalSourceFPGA : public SignalSourceBase
{
public:
Ad9361FpgaSignalSource(const ConfigurationInterface *configuration,
Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~Ad9361FpgaSignalSource();
void start() override;
~Adrv9361z7035SignalSourceFPGA();
inline size_t item_size() override
{
@@ -66,13 +63,9 @@ public:
gr::basic_block_sptr get_right_block() override;
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_rf_port_select = std::string("A_BALANCED");
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_manual_gain_rx1 = 64.0;
const double default_manual_gain_rx2 = 64.0;
@@ -84,35 +77,20 @@ private:
const uint32_t buffer_monitor_period_ms = 1000;
// buffer overflow and buffer monitoring initial delay
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
// sample block size when running in post-processing mode
const int sample_block_size = 16384;
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);
const int32_t switch_to_real_time_mode = 2;
void run_dynamic_bit_selection_process();
void run_buffer_monitor_process();
std::thread thread_file_to_dma;
mutable std::mutex dynamic_bit_selection_mutex;
mutable std::mutex buffer_monitor_mutex;
std::thread thread_dynamic_bit_selection;
std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_Switch> switch_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_DMA> dma_fpga;
std::mutex dma_mutex;
std::mutex dynamic_bit_selection_mutex;
std::mutex buffer_monitor_mutex;
Concurrent_Queue<pmt::pmt_t> *queue_;
std::string gain_mode_rx1_;
std::string gain_mode_rx2_;
@@ -120,8 +98,6 @@ private:
std::string filter_file_;
std::string filter_source_;
std::string filter_filename_;
std::string filename0_;
std::string filename1_;
double rf_gain_rx1_;
double rf_gain_rx2_;
@@ -130,41 +106,32 @@ private:
double tx_attenuation_db_;
uint64_t freq0_; // frequency of local oscillator for ADRV9361-A 0
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present)
uint64_t sample_rate_;
uint64_t bandwidth_;
uint64_t samples_to_skip_;
int64_t samples_;
uint64_t freq_dds_tx_hz_;
uint64_t freq_rf_tx_hz_;
uint64_t tx_bandwidth_;
float Fpass_;
float Fstop_;
uint32_t num_input_files_;
uint32_t dma_buff_offset_pos_;
uint32_t in_stream_;
uint32_t out_stream_;
int32_t switch_position_;
size_t item_size_;
bool enable_dds_lo_;
bool filter_auto_;
bool quadrature_;
bool rf_dc_;
bool bb_dc_;
bool rx1_enable_;
bool rx2_enable_;
bool enable_DMA_;
bool enable_dynamic_bit_selection_;
bool enable_ovf_check_buffer_monitor_active_;
bool dump_;
bool rf_shutdown_;
bool repeat_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
#endif // GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H

View File

@@ -18,9 +18,14 @@
#include "custom_udp_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <iostream>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -0,0 +1,581 @@
/*!
* \file dma_signal_source_fpga.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_signal_source_fpga.h"
#include "command_event.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <algorithm> // for std::min
#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;
DMASignalSourceFPGA::DMASignalSourceFPGA(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_Signal_Source_FPGA"s),
queue_(queue),
filename0_(configuration->property(role + ".filename", empty_string)),
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
samples_to_skip_(0),
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
{
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";
}
}
DMASignalSourceFPGA::~DMASignalSourceFPGA()
{
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 DMASignalSourceFPGA::start()
{
thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); });
}
void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue<pmt::pmt_t> *queue)
{
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 DMASignalSourceFPGA::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 DMASignalSourceFPGA::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void DMASignalSourceFPGA::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 DMASignalSourceFPGA::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr DMASignalSourceFPGA::get_right_block()
{
return {};
}

View File

@@ -0,0 +1,118 @@
/*!
* \file dma_signal_source_fpga.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_SIGNAL_SOURCE_FPGA_H
#define GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_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 DMASignalSourceFPGA : public SignalSourceBase
{
public:
DMASignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~DMASignalSourceFPGA();
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_SIGNAL_SOURCE_FPGA_H

View File

@@ -19,10 +19,14 @@
#include "configuration_interface.h"
#include "fifo_reader.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <gnuradio/blocks/file_source.h>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
@@ -30,8 +34,8 @@ FifoSignalSource::FifoSignalSource(ConfigurationInterface const* configuration,
std::string const& role, unsigned int in_streams, unsigned int out_streams,
[[maybe_unused]] Concurrent_Queue<pmt::pmt_t>* queue)
: SignalSourceBase(configuration, role, "Fifo_Signal_Source"s),
item_size_(sizeof(gr_complex)), // currenty output item size is always gr_complex
fifo_reader_(FifoReader::make(configuration->property(role + ".filename", "../data/example_capture.dat"s),
item_size_(sizeof(gr_complex)), // currently output item size is always gr_complex
fifo_reader_(FifoReader::make(configuration->property(role + ".filename", "./example_capture.dat"s),
configuration->property(role + ".sample_type", "ishort"s))),
dump_(configuration->property(role + ".dump", false)),
dump_filename_(configuration->property(role + ".dump_filename", "./data/signal_source.dat"s))

View File

@@ -18,7 +18,12 @@
#include "file_signal_source.h"
#include "gnss_sdr_string_literals.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -29,12 +29,16 @@
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <glog/logging.h>
#include <algorithm> // for std::max
#include <cmath> // for ceil, floor
#include <iostream> // for std::cout, std:cerr
#include <utility> // for std::move
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
@@ -44,8 +48,8 @@ FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std:
: SignalSourceBase(configuration, role, std::move(impl)),
queue_(queue),
role_(role),
filename_(configuration->property(role_ + ".filename"s, "../data/example_capture.dat"s)),
dump_filename_(configuration->property(role_ + ".dump_filename"s, "../data/my_capture.dat"s)),
filename_(configuration->property(role_ + ".filename"s, "./example_capture.dat"s)),
dump_filename_(configuration->property(role_ + ".dump_filename"s, "./my_capture.dat"s)),
item_type_(configuration->property(role_ + ".item_type"s, std::move(default_item_type))),
item_size_(0),
header_size_(configuration->property(role_ + ".header_size"s, uint64_t(0))),
@@ -93,7 +97,8 @@ FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std:
}
}
// override value with commandline flag, if present
// override value with commandline flag, if present
#if USE_GLOG_AND_GFLAGS
if (FLAGS_signal_source != "-")
{
filename_ = FLAGS_signal_source;
@@ -102,6 +107,16 @@ FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std:
{
filename_ = FLAGS_s;
}
#else
if (absl::GetFlag(FLAGS_signal_source) != "-")
{
filename_ = absl::GetFlag(FLAGS_signal_source);
}
if (absl::GetFlag(FLAGS_s) != "-")
{
filename_ = absl::GetFlag(FLAGS_s);
}
#endif
if (sampling_frequency_ == 0)
{
std::cerr << "Warning: parameter " << role_ << ".sampling_frequency is not set, this could lead to wrong results.\n"

View File

@@ -18,9 +18,14 @@
#include "file_timestamp_signal_source.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <string>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
FileTimestampSignalSource::FileTimestampSignalSource(const ConfigurationInterface* configuration,
@@ -29,7 +34,7 @@ FileTimestampSignalSource::FileTimestampSignalSource(const ConfigurationInterfac
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: FileSourceBase(configuration, role, "File_Timestamp_Signal_Source"s, queue, "byte"s),
timestamp_file_(configuration->property(role + ".timestamp_filename"s, "../data/example_capture_timestamp.dat"s)),
timestamp_file_(configuration->property(role + ".timestamp_filename"s, "./example_capture_timestamp.dat"s)),
timestamp_clock_offset_ms_(configuration->property(role + ".timestamp_clock_offset_ms"s, 0.0))
{
if (in_streams > 0)
@@ -41,11 +46,18 @@ FileTimestampSignalSource::FileTimestampSignalSource(const ConfigurationInterfac
LOG(ERROR) << "This implementation only supports one output stream";
}
// override value with commandline flag, if present
// override value with commandline flag, if present
#if USE_GLOG_AND_GFLAGS
if (FLAGS_timestamp_source != "-")
{
timestamp_file_ = FLAGS_timestamp_source;
}
#else
if (absl::GetFlag(FLAGS_timestamp_source) != "-")
{
timestamp_file_ = absl::GetFlag(FLAGS_timestamp_source);
}
#endif
}

View File

@@ -19,11 +19,16 @@
#include "flexiband_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <teleorbit/frontend.h>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
@@ -34,7 +39,7 @@ FlexibandSignalSource::FlexibandSignalSource(const ConfigurationInterface* confi
Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused)))
: SignalSourceBase(configuration, role, "Flexiband_Signal_Source"s), in_stream_(in_stream), out_stream_(out_stream)
{
const std::string default_item_type("byte");
const std::string default_item_type("gr_complex");
item_type_ = configuration->property(role + ".item_type", default_item_type);
const std::string default_firmware_file("flexiband_I-1b.bit");

View File

@@ -66,10 +66,10 @@ public:
gr::basic_block_sptr get_right_block(int RF_channel) override;
private:
boost::shared_ptr<gr::block> flexiband_source_;
gnss_shared_ptr<gr::block> flexiband_source_;
std::vector<boost::shared_ptr<gr::block>> char_to_float;
std::vector<boost::shared_ptr<gr::block>> float_to_complex_;
std::vector<gnss_shared_ptr<gr::block>> char_to_float;
std::vector<gnss_shared_ptr<gr::block>> float_to_complex_;
std::vector<gr::blocks::null_sink::sptr> null_sinks_;
std::string item_type_;

View File

@@ -24,12 +24,17 @@
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <glog/logging.h>
#include <algorithm> // for max
#include <exception>
#include <iostream>
#include <vector>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
Fmcomms2SignalSource::Fmcomms2SignalSource(const ConfigurationInterface *configuration,
@@ -70,7 +75,11 @@ Fmcomms2SignalSource::Fmcomms2SignalSource(const ConfigurationInterface *configu
rf_dc_(configuration->property(role + ".rf_dc", true)),
bb_dc_(configuration->property(role + ".bb_dc", true)),
filter_auto_(configuration->property(role + ".filter_auto", false)),
#if USE_GLOG_AND_GFLAGS
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)),
#else
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))),
#endif
dump_(configuration->property(role + ".dump", false))
{
if (filter_auto_)

View File

@@ -93,7 +93,7 @@ private:
double rf_gain_rx1_;
double rf_gain_rx2_;
uint64_t freq_; // frequency of local oscilator
uint64_t freq_; // frequency of local oscillator
uint64_t sample_rate_;
uint64_t bandwidth_;
uint64_t buffer_size_; // reception buffer

View File

@@ -0,0 +1,344 @@
/*!
* \file fmcomms5_signal_source_fpga.cc
* \brief Signal source for the Analog Devices FMCOMMS5 directly connected
* to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
* is selected in the configuration file.
* \authors <ul>
* <li> Javier Arribas, jarribas(at)cttc.es
* <li> Marc Majoral, mmajoral(at)cttc.es
* </ul>
*
* -----------------------------------------------------------------------------
*
* 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 "fmcomms5_signal_source_fpga.h"
#include "GPS_L1_CA.h"
#include "GPS_L5.h"
#include "ad9361_manager.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <algorithm> // for std::max
#include <chrono> // for std::chrono
#include <cmath> // for std::floor
#include <exception> // for std::exception
#include <iostream> // for std::cout
#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;
Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(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, "FMCOMMS5_Signal_Source_FPGA"s),
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)),
gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)),
rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)),
filter_source_(configuration->property(role + ".filter_source", std::string("Off"))),
filter_filename_(configuration->property(role + ".filter_filename", filter_file_)),
rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)),
rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)),
freq0_(configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ))),
freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))),
sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)),
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))),
Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))),
in_stream_(in_stream),
out_stream_(out_stream),
item_size_(sizeof(int8_t)),
quadrature_(configuration->property(role + ".quadrature", true)),
rf_dc_(configuration->property(role + ".rf_dc", true)),
bb_dc_(configuration->property(role + ".bb_dc", true)),
rx1_enable_(configuration->property(role + ".rx1_enable", true)),
rx2_enable_(configuration->property(role + ".rx2_enable", true)),
enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)),
enable_ovf_check_buffer_monitor_active_(true),
dump_(configuration->property(role + ".dump", false)),
#if USE_GLOG_AND_GFLAGS
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown))
#else
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown)))
#endif
{
const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) ||
(configuration->property("Channels_1B.count", 0) > 0));
const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) ||
(configuration->property("Channels_L5.count", 0) > 0) ||
(configuration->property("Channels_5X.count", 0) > 0));
const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1;
switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(switch_to_real_time_mode);
std::cout << "Sample rate: " << sample_rate_ << " Sps\n";
// some basic checks
if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2"))
{
std::cout << "Configuration parameter rf_port_select should take one of these values:\n";
std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n";
std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n';
rf_port_select_ = default_rf_port_select;
LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select;
}
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;
}
if (enable_rx1_band)
{
std::cout << "LO 0 frequency : " << freq0_ << " Hz\n";
}
if (enable_rx2_band)
{
std::cout << "LO 1 frequency : " << freq1_ << " 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;
}
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
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";
}
}
Fmcomms5SignalSourceFPGA::~Fmcomms5SignalSourceFPGA()
{
// cleanup and exit
if (rf_shutdown_)
{
std::cout << "* Disabling RX streaming channels\n";
try
{
if (!disable_ad9361_rx_local())
{
LOG(WARNING) << "Problem shutting down the AD9361 RX channels";
}
}
catch (const std::exception &e)
{
std::cerr << "Problem shutting down the AD9361 RX channels: " << e.what() << '\n';
}
}
// disable buffer overflow checking and buffer monitoring
{
std::lock_guard<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
}
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.join();
}
bool bit_selection_enabled = false;
{
std::lock_guard<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex);
bit_selection_enabled = enable_dynamic_bit_selection_;
}
if (bit_selection_enabled == true)
{
{
std::lock_guard<std::mutex> lock(dynamic_bit_selection_mutex);
enable_dynamic_bit_selection_ = false;
}
if (thread_dynamic_bit_selection.joinable())
{
thread_dynamic_bit_selection.join();
}
}
}
void Fmcomms5SignalSourceFPGA::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::lock_guard<std::mutex> lock(dynamic_bit_selection_mutex);
if (enable_dynamic_bit_selection_ == false)
{
dynamic_bit_selection_active = false;
}
}
}
void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process()
{
bool enable_ovf_check_buffer_monitor_active = true;
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms));
while (enable_ovf_check_buffer_monitor_active)
{
buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status();
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms));
std::lock_guard<std::mutex> lock(buffer_monitor_mutex);
if (enable_ovf_check_buffer_monitor_active_ == false)
{
enable_ovf_check_buffer_monitor_active = false;
}
}
}
void Fmcomms5SignalSourceFPGA::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void Fmcomms5SignalSourceFPGA::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 Fmcomms5SignalSourceFPGA::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr Fmcomms5SignalSourceFPGA::get_right_block()
{
return {};
}

View File

@@ -0,0 +1,130 @@
/*!
* \file fmcomms5_signal_source_fpga.h
* \brief Signal source for the Analog Devices FMCOMMS5 directly connected
* to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
* is selected in the configuration file.
*
* -----------------------------------------------------------------------------
*
* 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_FMCOMMS5_SIGNAL_SOURCE_FPGA_H
#define GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H
#include "concurrent_queue.h"
#include "fpga_buffer_monitor.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 Fmcomms5SignalSourceFPGA : public SignalSourceBase
{
public:
Fmcomms5SignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~Fmcomms5SignalSourceFPGA();
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 default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
const std::string default_rf_port_select = std::string("A_BALANCED");
const std::string default_gain_mode = std::string("slow_attack");
const double default_manual_gain_rx1 = 64.0;
const double default_manual_gain_rx2 = 64.0;
const uint64_t default_bandwidth = 12500000;
// perform dynamic bit selection every 500 ms by default
const uint32_t Gain_control_period_ms = 500;
// check buffer overflow and perform buffer monitoring every 1s by default
const uint32_t buffer_monitor_period_ms = 1000;
// buffer overflow and buffer monitoring initial delay
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
const int32_t switch_to_real_time_mode = 2;
void run_dynamic_bit_selection_process();
void run_buffer_monitor_process();
mutable std::mutex dynamic_bit_selection_mutex;
mutable std::mutex buffer_monitor_mutex;
std::thread thread_dynamic_bit_selection;
std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_Switch> switch_fpga;
std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga;
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
std::string gain_mode_rx1_;
std::string gain_mode_rx2_;
std::string rf_port_select_;
std::string filter_file_;
std::string filter_source_;
std::string filter_filename_;
double rf_gain_rx1_;
double rf_gain_rx2_;
uint64_t freq0_; // frequency of local oscillator for ADRV9361-A
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B
uint64_t sample_rate_;
uint64_t bandwidth_;
float Fpass_;
float Fstop_;
uint32_t in_stream_;
uint32_t out_stream_;
size_t item_size_;
bool quadrature_;
bool rf_dc_;
bool bb_dc_;
bool rx1_enable_;
bool rx2_enable_;
bool enable_dynamic_bit_selection_;
bool enable_ovf_check_buffer_monitor_active_;
bool dump_;
bool rf_shutdown_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H

View File

@@ -19,7 +19,12 @@
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
@@ -58,11 +63,18 @@ FourBitCpxFileSignalSource::FourBitCpxFileSignalSource(
LOG(ERROR) << "This implementation only supports one output stream";
}
// override value with commandline flag, if present
// override value with commandline flag, if present
#if USE_GLOG_AND_GFLAGS
if (FLAGS_timestamp_source != "-")
{
timestamp_file_ = FLAGS_timestamp_source;
}
#else
if (absl::GetFlag(FLAGS_timestamp_source) != "-")
{
timestamp_file_ = absl::GetFlag(FLAGS_timestamp_source);
}
#endif
}

View File

@@ -18,12 +18,16 @@
#include "gen_signal_source.h"
#include <boost/lexical_cast.hpp>
#include <glog/logging.h>
#include <gnuradio/io_signature.h>
#include <gnuradio/message.h>
#include <sstream>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
// Constructor
GenSignalSource::GenSignalSource(std::shared_ptr<GNSSBlockInterface> signal_generator,

View File

@@ -0,0 +1,239 @@
/*!
* \file ion_gsms_signal_source.h
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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 "ion_gsms_signal_source.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <gnuradio/blocks/copy.h>
#include <cstdlib>
#include <iostream>
#include <unordered_set>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
namespace
{
std::vector<std::string> parse_comma_list(const std::string& str)
{
std::vector<std::string> list{};
std::size_t prev_comma_at{0};
while (prev_comma_at < str.size())
{
std::size_t comma_at = str.find_first_of(',', prev_comma_at);
if (comma_at == std::string::npos)
{
comma_at = str.size();
}
list.emplace_back(str.substr(prev_comma_at, (comma_at - prev_comma_at)));
prev_comma_at = comma_at + 1;
}
return list;
}
} // anonymous namespace
IONGSMSSignalSource::IONGSMSSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: SignalSourceBase(configuration, role, "ION_GSMS_Signal_Source"s),
stream_ids_(parse_comma_list(configuration->property(role + ".streams"s, ""s))),
metadata_filepath_(configuration->property(role + ".metadata_filename"s, "./example_capture_metadata.sdrx"s)),
in_streams_(in_streams),
out_streams_(out_streams)
{
if (in_streams_ > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_streams_ <= 0)
{
LOG(ERROR) << "A signal source does not have an output stream";
}
// Parse XML metadata file
load_metadata();
// Make source vector
sources_ = make_stream_sources(stream_ids_);
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i)
{
copy_blocks_.emplace_back(gr::blocks::copy::make(source->output_stream_item_size(i)));
valves_.emplace_back(gnss_sdr_make_valve(source->output_stream_item_size(i), source->output_stream_total_sample_count(i), queue));
}
}
}
void IONGSMSSignalSource::load_metadata()
{
metadata_ = std::make_shared<GnssMetadata::Metadata>();
try
{
GnssMetadata::XmlProcessor xml_proc;
if (!xml_proc.Load(metadata_filepath_.c_str(), false, *metadata_))
{
LOG(WARNING) << "Could not load XML metadata file " << metadata_filepath_;
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
}
catch (GnssMetadata::ApiException& e)
{
LOG(WARNING) << "API Exception while loading XML metadata file: " << std::to_string(e.Error());
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << std::to_string(e.Error()) << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
catch (std::exception& e)
{
LOG(WARNING) << "Exception while loading XML metadata file: " << e.what();
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << e.what() << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
}
std::vector<IONGSMSFileSource::sptr> IONGSMSSignalSource::make_stream_sources(const std::vector<std::string>& stream_ids) const
{
std::vector<IONGSMSFileSource::sptr> sources{};
for (const auto& file : metadata_->Files())
{
for (const auto& lane : metadata_->Lanes())
{
if (lane.Id() == file.Lane().Id())
{
for (const auto& block : lane.Blocks())
{
bool block_done = false;
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
auto source = gnss_make_shared<IONGSMSFileSource>(
metadata_filepath_,
file,
block,
stream_ids);
sources.push_back(source);
// This file source will take care of any other matching streams in this block
// We can skip the rest of this block
block_done = true;
break;
}
}
if (block_done)
{
break;
}
}
if (block_done)
{
break;
}
}
}
break;
}
}
}
return sources;
}
void IONGSMSSignalSource::connect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->connect(source, i, copy_blocks_[cumulative_index], 0);
top_block->connect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0);
}
}
}
void IONGSMSSignalSource::disconnect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->disconnect(source, i, copy_blocks_[cumulative_index], 0);
top_block->disconnect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0);
}
}
}
gr::basic_block_sptr IONGSMSSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
// return gr_basic_block_sptr();
return IONGSMSFileSource::sptr();
}
gr::basic_block_sptr IONGSMSSignalSource::get_right_block()
{
return get_right_block(0);
}
gr::basic_block_sptr IONGSMSSignalSource::get_right_block(int RF_channel)
{
if (RF_channel < 0 || RF_channel >= static_cast<int>(copy_blocks_.size()))
{
LOG(WARNING) << "'RF_channel' out of bounds while trying to get signal source right block.";
return valves_[0];
}
return valves_[RF_channel];
}

View File

@@ -0,0 +1,85 @@
/*!
* \file ion_gsms_signal_source.h
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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_ION_GSMS_SIGNAL_SOURCE_H
#define GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H
#include "configuration_interface.h"
#include "file_source_base.h"
#include "gnss_sdr_timestamp.h"
#include "ion_gsms.h"
#include <GnssMetadata.h>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
/*!
* \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface
*/
class IONGSMSSignalSource : public SignalSourceBase
{
public:
IONGSMSSignalSource(const ConfigurationInterface* configuration, const std::string& role,
unsigned int in_streams, unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue);
~IONGSMSSignalSource() override = default;
protected:
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;
gr::basic_block_sptr get_right_block(int RF_channel) override;
inline size_t item_size() override
{
return (*sources_.begin())->output_stream_item_size(0);
}
private:
std::vector<IONGSMSFileSource::sptr> make_stream_sources(const std::vector<std::string>& stream_ids) const;
void load_metadata();
std::vector<std::string> stream_ids_;
std::vector<IONGSMSFileSource::sptr> sources_;
std::vector<gnss_shared_ptr<gr::block>> copy_blocks_;
std::vector<gnss_shared_ptr<gr::block>> valves_;
std::string metadata_filepath_;
std::shared_ptr<GnssMetadata::Metadata> metadata_;
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
std::string timestamp_file_;
uint32_t in_streams_;
uint32_t out_streams_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H

View File

@@ -18,9 +18,15 @@
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include "labsat23_source.h"
#include <glog/logging.h>
#include <iostream>
#include <sstream>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -20,10 +20,15 @@
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
LimesdrSignalSource::LimesdrSignalSource(const ConfigurationInterface* configuration,

View File

@@ -0,0 +1,464 @@
/*!
* \file max2771_evkit_signal_source_fpga.cc
* \brief Signal source for the MAX2771EVKIT evaluation board connected directly
* to FPGA accelerators.
* This source implements only the MAX2771 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
*
* -----------------------------------------------------------------------------
*
* 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 "max2771_evkit_signal_source_fpga.h"
#include "GPS_L1_CA.h"
#include "GPS_L2C.h"
#include "GPS_L5.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <algorithm> // for std::max
#include <chrono> // for std::chrono
#include <cmath> // for std::floor
#include <exception> // for std::exception
#include <iostream> // for std::cout
#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;
MAX2771EVKITSignalSourceFPGA::MAX2771EVKITSignalSourceFPGA(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, "MAX2771_EVKIT_Signal_Source_FPGA"s),
freq_(configuration->property(role + ".freq", static_cast<uint64_t>(GPS_L1_FREQ_HZ))),
sample_rate_(configuration->property(role + ".sampling_frequency", default_sampling_rate)),
in_stream_(in_stream),
out_stream_(out_stream),
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
filter_order_(configuration->property(role + ".filter_order", default_filter_order)),
gain_in_(configuration->property(role + ".PGA_gain", default_PGA_gain_value)),
item_size_(sizeof(int8_t)),
chipen_(true),
if_filter_gain_(configuration->property(role + ".enable_IF_filter_gain", true)),
LNA_active_(configuration->property(role + ".LNA_active", false)),
enable_agc_(configuration->property(role + ".enable_AGC", true)),
enable_ovf_check_buffer_monitor_active_(true),
dump_(configuration->property(role + ".dump", false)),
#if USE_GLOG_AND_GFLAGS
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown))
#else
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown)))
#endif
{
// some basic checks
if (freq_ != GPS_L1_FREQ_HZ and freq_ != GPS_L2_FREQ_HZ and freq_ != GPS_L5_FREQ_HZ)
{
std::cout << "Configuration parameter freq should take values " << GPS_L1_FREQ_HZ << ", " << GPS_L2_FREQ_HZ << ", or " << GPS_L5_FREQ_HZ << "\n";
std::cout << "Error: provided value freq = " << freq_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value freq = " << GPS_L1_FREQ_HZ << '\n';
LOG(WARNING) << "Invalid configuration value for freq parameter. Set to freq = " << GPS_L1_FREQ_HZ;
freq_ = GPS_L1_FREQ_HZ;
}
if (sample_rate_ != 4092000 and sample_rate_ != 8184000 and sample_rate_ != 16368000 and sample_rate_ != 32736000)
{
std::cout << "Configuration parameter sampling_frequency should take values 4092000, 8184000, 16368000, or 32736000\n";
std::cout << "Error: provided value sampling_frequency = " << sample_rate_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value sampling_frequency = " << default_sampling_rate << '\n';
LOG(WARNING) << "Invalid configuration value for sampling_frequency parameter. Set to sampling_frequency = " << default_sampling_rate;
sample_rate_ = default_sampling_rate;
}
if (bandwidth_ != 2500000 and bandwidth_ != 4200000 and bandwidth_ != 8700000 and bandwidth_ != 16400000 and bandwidth_ != 23400000 and bandwidth_ != 36000000)
{
std::cout << "Configuration parameter bandwidth can only take the following values: 2500000, 4200000, 8700000, 16400000, 23400000, and 36000000 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';
LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth = " << default_bandwidth;
bandwidth_ = default_bandwidth;
}
if (filter_order_ != 3 and filter_order_ != 5)
{
std::cout << "Configuration parameter filter_order should take values 3 or 5\n";
std::cout << "Error: provided value filter_order = " << filter_order_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value filter_order = " << default_filter_order << '\n';
LOG(WARNING) << "Invalid configuration value for filter_order parameter. Set to filter_order = " << default_filter_order;
filter_order_ = default_filter_order;
}
if (gain_in_ > max_PGA_gain_value)
{
std::cout << "Configuration parameter PGA_gain should be up to " << max_PGA_gain_value << "\n";
std::cout << "Error: provided value PGA_gain = " << gain_in_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value PGA_gain = " << default_PGA_gain_value << '\n';
LOG(WARNING) << "Invalid configuration value for PGA_gain parameter. Set to PGA_gain = " << default_PGA_gain_value;
gain_in_ = default_PGA_gain_value;
}
std::vector<uint32_t> register_values = setup_regs();
spidev_fpga = std::make_shared<Fpga_spidev>();
if (spidev_fpga->SPI_open())
{
std::cerr << "Cannot open SPI device\n";
// stop the receiver
queue->push(pmt::make_any(command_event_make(200, 0)));
return;
}
if (configure(register_values))
{
std::cerr << "Error configuring the MAX2771 device " << '\n';
}
if (spidev_fpga->SPI_close())
{
std::cerr << "Error closing SPI device " << '\n';
}
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(); });
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";
}
}
std::vector<uint32_t> MAX2771EVKITSignalSourceFPGA::setup_regs(void)
{
auto register_values = std::vector<uint32_t>(MAX2771_NUM_REGS);
uint32_t LNA_mode = (LNA_active_) ? 0x0 : 0x2;
uint32_t Filter_Bandwidth;
switch (bandwidth_)
{
case 2500000:
Filter_Bandwidth = 0x0;
break;
case 4200000:
Filter_Bandwidth = 0x2;
break;
case 8700000:
Filter_Bandwidth = 0x1;
break;
case 16400000:
Filter_Bandwidth = 0x7;
break;
case 23400000:
Filter_Bandwidth = 0x3;
break;
case 36000000:
Filter_Bandwidth = 0x4;
break;
default:
Filter_Bandwidth = 0x0; // default bandwidth
}
uint32_t chipen_select = (chipen_) ? 0x1 : 0x0;
uint32_t Filter_order_sel = (filter_order_ == 5) ? 0x0 : 0x1;
uint32_t IF_filter_gain_sel = (if_filter_gain_) ? 0x1 : 0x0;
register_values[0] = // configuration 1 register
(chipen_select << 31) +
(IDLE << 30) +
(0x8 << 26) + // reserved
(0x8 << 22) + // reserved
(0x2 << 20) + // reserved
(0x1 << 18) + // reserved
(MIXPOLE << 17) +
(LNA_mode << 15) +
(MIXERMODE << 13) +
(FCEN << 6) +
(Filter_Bandwidth << 3) +
(Filter_order_sel << 2) +
(FCENX << 1) +
IF_filter_gain_sel;
uint32_t AGC_mode = (enable_agc_) ? 0x0 : 0x2;
register_values[1] = // configuration 2 register
(0x0 << 31) + // reserved
(0x1 << 29) + // reserved
(ANAIMON << 28) +
(IQEN << 27) +
(GAINREF << 15) +
(SPI_SDIO_CONFIG << 13) +
(AGC_mode << 11) +
(FORMAT << 9) +
(BITS << 6) +
(DRVCFG << 4) +
(0x1 << 3) + // reserved
(0x0 << 2) + // reserved
DIEID;
register_values[2] = // configuration 3 register
(0x0 << 28) + // reserved
(gain_in_ << 22) +
(0x1 << 21) + // reserved
(HILOADEN << 20) +
(0x1 << 19) + // reserved
(0x1 << 18) + // reserved
(0x1 << 17) + // reserved
(0x1 << 16) + // reserved
(FHIPEN << 15) +
(0x0 << 14) + // reserved
(PGAIEN << 13) +
(PGAQEN << 12) +
(STRMEN << 11) +
(STRMSTART << 10) +
(STRMSTOP << 9) +
(0x7 << 6) + // reserved
(STRMBITS << 4) +
(STAMPEN << 3) +
(TIMESYNCEN << 2) +
(DATASYNCEN << 1) +
STRMRST;
uint32_t clock_out_div_ratio;
switch (sample_rate_)
{
case 4092000:
clock_out_div_ratio = 0x1; // XTAL frequency /4
break;
case 8184000:
clock_out_div_ratio = 0x2; // XTAL frequency /2
break;
case 16368000:
clock_out_div_ratio = 0x3; // XTAL frequency
break;
case 32736000:
clock_out_div_ratio = 0x0; // XTAL Frequency x2
break;
default:
clock_out_div_ratio = 0x1; // default XTAL frequency
}
register_values[3] = // PLL configuration register
(clock_out_div_ratio << 29) +
(LOBAND << 28) +
(0x1 << 27) + // reserved
(0x0 << 26) + // reserved
(0x0 << 25) + // reserved
(REFOUTEN << 24) +
(0x1 << 23) + // reserved
(0x0 << 21) + // reserved
(IXTAL << 19) +
(0x10 << 14) + // reserved
(0x0 << 13) + // reserved
(0x0 << 10) + // reserved
(ICP << 9) +
(0x0 << 8) + // reserved
(0x0 << 7) + // reserved
(0x0 << 4) + // reserved
(INT_PLL << 3) +
(PWRSAV << 2) +
(0x0 << 1) + // reserved
0x0; // reserved
uint32_t freq_sel;
switch (freq_)
{
case static_cast<uint64_t>(GPS_L1_FREQ_HZ):
freq_sel = 0x604;
break;
case static_cast<uint64_t>(GPS_L2_FREQ_HZ):
freq_sel = 0x4B0;
break;
case static_cast<uint64_t>(GPS_L5_FREQ_HZ):
freq_sel = 0x47E;
break;
default:
freq_sel = 0x604;
}
register_values[4] = // PLL integer division register
(0x0 << 28) + // reserved
(freq_sel << 13) +
(RDIV << 3) +
0x0; // reserved
register_values[5] = // PLL fractional division register
(0x0 << 28) + // reserved
(FDIV << 8) +
(0x7 << 4) + // reserved
(0x0 << 3) + // reserved
(0x0 << 2) + // reserved
(0x0 << 1) + // reserved
0x0; // reserved
register_values[6] = // DSP interface register
(0x0 << 28) + // reserved
0x8000000; // reserved
register_values[7] = // clock configuration 1 register
(0x0 << 29) + // reserved
(EXTADCCLK << 28) +
(REFCLK_L_CNT << 16) +
(REFCLK_M_CNT << 4) +
(FCLKIN << 3) +
(ADCCLK << 2) +
(0x1 << 1) + // reserved
MODE;
register_values[8] = TEST_MODE_1_REG_VAL; // test mode 1 register
register_values[9] = TEST_MODE_2_REG_VAL; // test mode 2 register
register_values[10] = // clock configuration 2 register
(0x0 << 29) + // reserved
(0x0 << 28) + // reserved
(ADCCLK_L_CNT << 16) +
(ADCCLK_M_CNT << 4) +
(PRE_FRACDIV_SEL << 3) +
(CLKOUT_SEL << 2) +
0x0; // reserved
return register_values;
}
bool MAX2771EVKITSignalSourceFPGA::configure(std::vector<uint32_t> register_values)
{
// write the registers
std::cerr << "Configuring MAX2771 registers" << std::endl;
uint32_t status = 0;
for (uint32_t k = 0; k < register_values.size(); k++)
{
status = spidev_fpga->write_reg32(k, register_values[k]);
if (status)
{
std::cerr << "Error writing the MAX2771 registers" << std::endl;
break;
}
}
// Read the registers and verify that the values are correctly written
std::vector<uint32_t> reg_read = std::vector<uint32_t>(register_values.size());
for (uint8_t n = 0; n < register_values.size(); ++n)
{
status = spidev_fpga->read_reg32(n, &reg_read[n]);
if (status)
{
std::cerr << "Error reading the MAX2771 registers" << std::endl;
return status;
}
else
{
if (reg_read[n] != register_values[n])
{
std::cerr << "Error: Failed to verify the MAX2771 registers " << std::endl;
return -1;
}
}
}
return 0;
}
MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA()
{
// cleanup and exit
if (rf_shutdown_)
{
chipen_ = false;
std::cout << "* MAX2771 Disabling RX streaming channels\n";
std::vector<uint32_t> register_values = setup_regs();
if (spidev_fpga->SPI_open())
{
std::cerr << "Cannot open SPI device\n";
return;
}
if (configure(register_values))
{
std::cerr << "Error disabling the MAX2771 device " << '\n';
}
if (spidev_fpga->SPI_close())
{
std::cerr << "Error closing SPI device " << '\n';
}
}
// disable buffer overflow checking and buffer monitoring
{
std::lock_guard<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
}
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.join();
}
}
void MAX2771EVKITSignalSourceFPGA::run_buffer_monitor_process()
{
bool enable_ovf_check_buffer_monitor_active = true;
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms));
while (enable_ovf_check_buffer_monitor_active)
{
buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status();
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms));
std::lock_guard<std::mutex> lock(buffer_monitor_mutex);
if (enable_ovf_check_buffer_monitor_active_ == false)
{
enable_ovf_check_buffer_monitor_active = false;
}
}
}
void MAX2771EVKITSignalSourceFPGA::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void MAX2771EVKITSignalSourceFPGA::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 MAX2771EVKITSignalSourceFPGA::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr MAX2771EVKITSignalSourceFPGA::get_right_block()
{
return {};
}

View File

@@ -0,0 +1,162 @@
/*!
* \file max2771_evkit_signal_source_fpga.h
* \brief Signal source for the MAX2771EVKIT evaluation board connected directly
* to FPGA accelerators.
* This source implements only the MAX2771 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
*
* -----------------------------------------------------------------------------
*
* 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_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H
#define GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H
#include "command_event.h"
#include "concurrent_queue.h"
#include "fpga_buffer_monitor.h"
#include "fpga_spidev.h"
#include "gnss_block_interface.h"
#include "signal_source_base.h"
#include <pmt/pmt.h> // for pmt::pmt_t
#include <cstdint> // for fixed-width integer types
#include <memory> // for smart pointers
#include <mutex> // for mutex
#include <string> // for strings
#include <thread> // for threads
#include <vector> // for std::vector
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
class ConfigurationInterface;
class MAX2771EVKITSignalSourceFPGA : public SignalSourceBase
{
public:
MAX2771EVKITSignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~MAX2771EVKITSignalSourceFPGA();
std::vector<uint32_t> setup_regs(void);
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 default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
const uint64_t default_bandwidth = 2500000;
const uint32_t default_filter_order = 5;
const uint64_t default_sampling_rate = 4092000;
const uint32_t default_PGA_gain_value = 0x3A; // default PGA gain when AGC is off
// max PGA gain value
const uint32_t max_PGA_gain_value = 0x3F;
// check buffer overflow and perform buffer monitoring every 1s by default
const uint32_t buffer_monitor_period_ms = 1000;
// buffer overflow and buffer monitoring initial delay
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
// MAX2771 number of configuration registers
const uint32_t MAX2771_NUM_REGS = 11;
// MAX2771 configuration register fields
const uint32_t NUM_FREQ_BANDS = 1;
const uint32_t IDLE = 0x0; // Idle mode disabled
const uint32_t MIXPOLE = 0x0; // set the passive filter pole at mixer output at 13 MHz.
const uint32_t MIXERMODE = 0x0; // L1 band enabled
const uint32_t FCEN = 0x58; // Center frequency not used when in low-pass filter mode. Set to default value.
const uint32_t FCENX = 0x0; // POlyphase filter selection set to Lowpass filter
const uint32_t ANAIMON = 0x0; // analog monitor disabled
const uint32_t IQEN = 0x1; // I and Q channels enable
const uint32_t GAINREF = 0xAA; // AGC Gain ref
const uint32_t SPI_SDIO_CONFIG = 0x0; // SPI SDIO config when tri-stated: nothing applied
const uint32_t FORMAT = 0x1; // sign and magnitude
const uint32_t BITS = 0x2; // number of bits in the ADC = 2
const uint32_t DRVCFG = 0x0; // output driver configuration = CMOS Logic
const uint32_t DIEID = 0x0; // identifies version of IC
const uint32_t HILOADEN = 0x0; // disable output driver for high loads
const uint32_t FHIPEN = 0x1; // enable highpass coupling between filter and PGA.
const uint32_t PGAIEN = 0x1; // I-Channel PGA Enable
const uint32_t PGAQEN = 0x1; // Q-Channel PGA Enable
const uint32_t STRMEN = 0x0; // disable DSP interface for serial streaming of data
const uint32_t STRMSTART = 0x0; // the rising edge of this bit enables data streaming to the output, clock, data, sync and frame sync outputs.
const uint32_t STRMSTOP = 0x0; // the rising edge of this bit disables data streaming to the output, clock, data sync and frame sync outputs.
const uint32_t STRMBITS = 0x1; // number of bits to be streamed: I MSB, I LSB
const uint32_t STAMPEN = 0x1; // enable frame number insertion
const uint32_t TIMESYNCEN = 0x1; // enable the output of the time sync pulses at all times when streaming is enabled.
const uint32_t DATASYNCEN = 0x0; // disable the sync pulses at the DATASYNC output
const uint32_t STRMRST = 0x0; // counter reset not active
const uint32_t LOBAND = 0x0; // L1 band
const uint32_t REFOUTEN = 0x1; // Output clock buffer enable
const uint32_t IXTAL = 0x1; // XTAL osscillator/buffer set to normal current
const uint32_t ICP = 0x0; // charge pump current selection set to 0.5 mA
const uint32_t INT_PLL = 0x1; // PLL mode set to integer-N PLL
const uint32_t PWRSAV = 0x0; // PLL power save mode disabled
const uint32_t RDIV = 0x10; // Set the PLL reference division ratio such that the L1 band is tuned to 1575.42 Mhz
const uint32_t FDIV = 0x80000; // PLL fractional division ratio not used. Set to default value
const uint32_t EXTADCCLK = 0x0; // use internally generated clock
const uint32_t REFCLK_L_CNT = 0x100; // set the L counter of the reference clock configuration to its default value
const uint32_t REFCLK_M_CNT = 0x61B; // set the M counter of the reference clock configuration to its default value
const uint32_t FCLKIN = 0x0; // fractional clock divider set to default value
const uint32_t ADCCLK = 0x0; // ADC clock selection set to reference clock divider/multiplier
const uint32_t MODE = 0x0; // DSP interface mode selection
const uint32_t ADCCLK_L_CNT = 0x100; // set the L counter of the ADC clock configuration to its default value
const uint32_t ADCCLK_M_CNT = 0x61B; // set the M counter of the ADC clock configuration to its default value
const uint32_t PRE_FRACDIV_SEL = 0x0; // bypass fractional clock divider
const uint32_t CLKOUT_SEL = 0x1; // CLKOUT selection set to ADC clock
// MAX2771 configuration register registers
const uint32_t TEST_MODE_1_REG_VAL = 0x01E0F401; // reserved
const uint32_t TEST_MODE_2_REG_VAL = 0x00000002;
bool configure(std::vector<uint32_t> register_values);
void run_buffer_monitor_process();
mutable std::mutex buffer_monitor_mutex;
std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
std::shared_ptr<Fpga_spidev> spidev_fpga;
uint64_t freq_; // frequency of local oscillator
uint64_t sample_rate_;
uint32_t in_stream_;
uint32_t out_stream_;
uint32_t bandwidth_; // 2500000, 4200000, 8700000, 16400000, 23400000, 36000000
uint32_t filter_order_; // 3, 5
uint32_t gain_in_; // 0 to 0x3F
size_t item_size_; // 1
bool chipen_; // chip enable
bool if_filter_gain_; // true, false
bool LNA_active_; // true, false
bool enable_agc_; // true, false
bool enable_ovf_check_buffer_monitor_active_;
bool dump_;
bool rf_shutdown_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H

View File

@@ -20,13 +20,18 @@
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <glog/logging.h>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream> // for std::cerr
#include <utility>
#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;

View File

@@ -18,7 +18,12 @@
#include "nsr_file_signal_source.h"
#include "gnss_sdr_string_literals.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -21,10 +21,15 @@
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
@@ -81,6 +86,23 @@ OsmosdrSignalSource::OsmosdrSignalSource(const ConfigurationInterface* configura
std::cout << "PLL Frequency tune error: " << osmosdr_source_->get_center_freq() - freq_ << " [Hz]...\n";
LOG(INFO) << "PLL Frequency tune error: " << osmosdr_source_->get_center_freq() - freq_ << " [Hz]...\n";
// Set IQ balance and DC offset modes
// iq balance correction mode: 0 = Off, 1 = Manual, 2 = Automatic
// dc offset correction mode: 0 = Off, 1 = Manual, 2 = Automatic
int iq_balance_mode = configuration->property(role + ".iq_balance_mode", 2);
if (iq_balance_mode < 0 || iq_balance_mode > 2)
{
iq_balance_mode = 2;
}
int dc_offset_mode = configuration->property(role + ".dc_offset_mode", 2);
if (dc_offset_mode < 0 || dc_offset_mode > 2)
{
dc_offset_mode = 2;
}
osmosdr_source_->set_iq_balance_mode(iq_balance_mode);
osmosdr_source_->set_dc_offset_mode(dc_offset_mode);
// 4. set rx gain
if (this->AGC_enabled_ == true)
{
@@ -123,10 +145,9 @@ OsmosdrSignalSource::OsmosdrSignalSource(const ConfigurationInterface* configura
if (if_bw_ > 0.0)
{
osmosdr_source_->set_bandwidth(if_bw_, 0);
// Get actual bandwidth
std::cout << "Actual Bandwidth: " << osmosdr_source_->get_bandwidth(0) << " [Hz]...\n";
}
// Get actual bandwidth
std::cout << "Actual Bandwidth: " << osmosdr_source_->get_bandwidth(0) << " [Hz]...\n";
}
else
{

View File

@@ -20,9 +20,13 @@
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <glog/logging.h>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -87,7 +87,7 @@ private:
std::string item_type_;
double rf_gain_;
int64_t samples_;
uint64_t freq_; // frequency of local oscilator
uint64_t freq_; // frequency of local oscillator
uint64_t sample_rate_;
uint64_t bandwidth_;
uint64_t buffer_size_; // reception buffer

View File

@@ -18,11 +18,15 @@
#include "concurrent_queue.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <pmt/pmt.h>
#include <dbfcttc/raw_array.h>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -22,11 +22,16 @@
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <cstdint>
#include <iostream>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
RtlTcpSignalSource::RtlTcpSignalSource(const ConfigurationInterface* configuration,

View File

@@ -17,8 +17,13 @@
#include "spir_file_signal_source.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#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;

View File

@@ -19,13 +19,19 @@
#include "spir_gss6450_file_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <utility>
#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;
SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(const ConfigurationInterface* configuration,
@@ -48,8 +54,8 @@ SpirGSS6450FileSignalSource::SpirGSS6450FileSignalSource(const ConfigurationInte
enable_throttle_control_(configuration->property(role + ".enable_throttle_control", false)),
endian_swap_(configuration->property(role + ".endian", false))
{
const std::string default_filename("../data/my_capture.dat");
const std::string default_dump_filename("../data/my_capture_dump.dat");
const std::string default_filename("./my_capture.dat");
const std::string default_dump_filename("./my_capture_dump.dat");
filename_ = configuration->property(role + ".filename", default_filename);
dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename);

View File

@@ -17,7 +17,12 @@
#include "two_bit_cpx_file_signal_source.h"
#include "gnss_sdr_string_literals.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -19,9 +19,14 @@
#include "two_bit_packed_file_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
#include <gnuradio/blocks/char_to_float.h>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
TwoBitPackedFileSignalSource::TwoBitPackedFileSignalSource(

View File

@@ -21,13 +21,18 @@
#include "gnss_sdr_filesystem.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <glog/logging.h>
#include <uhd/exception.hpp>
#include <uhd/types/device_addr.hpp>
#include <volk/volk.h>
#include <iostream>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -17,7 +17,12 @@
#include "zmq_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_string_literals.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;

View File

@@ -10,17 +10,16 @@ if(ENABLE_RAW_UDP AND PCAP_FOUND)
list(APPEND OPT_DRIVER_HEADERS gr_complex_ip_packet_source.h)
endif()
if(ENABLE_AD936X_SDR)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gr_complex_ip_packet_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h)
endif()
if(ENABLE_PLUTOSDR)
if(ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_iio_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h)
endif()
if(ENABLE_ION)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ion_gsms.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ion_gsms.h)
endif()
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
fifo_reader.cc
unpack_byte_2bit_samples.cc
@@ -75,10 +74,15 @@ target_link_libraries(signal_source_gr_blocks
PRIVATE
algorithms_libs
core_libs
Gflags::gflags
Glog::glog
)
if(ENABLE_GLOG_AND_GFLAGS)
target_link_libraries(signal_source_gr_blocks PRIVATE Gflags::gflags Glog::glog)
target_compile_definitions(signal_source_gr_blocks PRIVATE -DUSE_GLOG_AND_GFLAGS=1)
else()
target_link_libraries(signal_source_gr_blocks PRIVATE absl::flags absl::log)
endif()
target_include_directories(signal_source_gr_blocks
PUBLIC
${GNSSSDR_SOURCE_DIR}/src/core/receiver
@@ -128,6 +132,14 @@ if(USE_BOOST_BIND_PLACEHOLDERS)
)
endif()
# Fix for Boost Asio > 1.86. address::from_string was deprecated in Boost 1.71
if(Boost_VERSION_STRING VERSION_LESS 1.71.0)
target_compile_definitions(signal_source_gr_blocks
PRIVATE
-DBOOST_ASIO_USE_FROM_STRING=1
)
endif()
if(USE_GENERIC_LAMBDAS)
set(has_generic_lambdas HAS_GENERIC_LAMBDA=1)
set(no_has_generic_lambdas HAS_GENERIC_LAMBDA=0)

View File

@@ -1,6 +1,7 @@
/*!
* \file ad936x_iio_source.cc
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the
* AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
@@ -33,23 +34,23 @@
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string& pluto_uri_,
const std::string& board_type_,
int64_t bandwidth_,
int64_t sample_rate_,
int64_t freq_,
const std::string& rf_port_select_,
const std::string& rf_filter,
const std::string& gain_mode_rx0_,
const std::string& gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
int64_t freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
const std::string& fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
@@ -85,9 +86,10 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
tx_lo_channel_));
}
void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector<std::fstream> *files_out)
void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples* samples_in, int nchannels, std::vector<std::fstream>* files_out)
{
int32_t current_byte = 0;
uint32_t current_byte = 0;
int16_t ch = 0;
// std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n";
while (current_byte < samples_in->n_bytes)
@@ -101,24 +103,25 @@ void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samp
}
}
ad936x_iio_source::ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string& pluto_uri_,
const std::string& board_type_,
int64_t bandwidth_,
int64_t sample_rate_,
int64_t freq_,
const std::string& rf_port_select_,
const std::string& rf_filter,
const std::string& gain_mode_rx0_,
const std::string& gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
int64_t freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
const std::string& fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
@@ -171,54 +174,81 @@ ad936x_iio_source::ad936x_iio_source(
case 16:
{
std::cout << "FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("ssize=16\n") == false)
{
std::cout << "cmd send error!\n";
}
break;
}
case 8:
{
std::cout << "FPGA sample size set to 8 bits per sample.\n";
if (pps_rx->send_cmd("ssize=8\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("ssize=8\n") == false)
{
std::cout << "cmd send error!\n";
}
break;
}
case 4:
{
std::cout << "FPGA sample size set to 4 bits per sample.\n";
if (pps_rx->send_cmd("ssize=4\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("ssize=4\n") == false)
{
std::cout << "cmd send error!\n";
}
break;
}
case 2:
{
std::cout << "FPGA sample size set to 2 bits per sample.\n";
if (pps_rx->send_cmd("ssize=2\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("ssize=2\n") == false)
{
std::cout << "cmd send error!\n";
}
break;
}
default:
{
std::cout << "WARNING: Unsupported ssize. FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("ssize=16") == false)
{
std::cout << "cmd send error!\n";
}
}
}
if (bshift_ >= 0 and bshift_ <= 14)
{
std::cout << "FPGA sample bits shift left set to " + std::to_string(bshift_) + " positions.\n";
if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false)
{
std::cout << "cmd send error!\n";
}
}
else
{
std::cout << "WARNING: Unsupported bshift. FPGA sample bits shift left set to 0.\n";
if (pps_rx->send_cmd("bshift=0\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("bshift=0\n") == false)
{
std::cout << "cmd send error!\n";
}
}
if (spattern_ == true)
{
std::cout << "FPGA debug sample pattern is active!.\n";
if (pps_rx->send_cmd("spattern=1\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("spattern=1\n") == false)
{
std::cout << "cmd send error!\n";
}
}
else
{
std::cout << "FPGA debug sample pattern disabled.\n";
if (pps_rx->send_cmd("spattern=0\n") == false) std::cout << "cmd send error!\n";
if (pps_rx->send_cmd("spattern=0\n") == false)
{
std::cout << "cmd send error!\n";
}
}
}
else
@@ -238,7 +268,7 @@ ad936x_iio_source::ad936x_iio_source(
exit(1);
}
}
catch (std::exception const &ex)
catch (std::exception const& ex)
{
std::cerr << "STD exception: " << ex.what() << std::endl;
exit(1);
@@ -267,6 +297,7 @@ ad936x_iio_source::ad936x_iio_source(
// }
}
ad936x_iio_source::~ad936x_iio_source()
{
// Terminate PPS thread
@@ -284,6 +315,7 @@ bool ad936x_iio_source::start()
return ad936x_custom->start_sample_rx(false);
}
bool ad936x_iio_source::stop()
{
std::cout << "stopping ad936x_iio_source...\n";
@@ -291,17 +323,17 @@ bool ad936x_iio_source::stop()
return true;
}
int ad936x_iio_source::general_work(int noutput_items,
__attribute__((unused)) gr_vector_int &ninput_items,
__attribute__((unused)) gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
__attribute__((unused)) gr_vector_int& ninput_items,
__attribute__((unused)) gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
std::shared_ptr<ad936x_iio_samples> current_buffer;
ad936x_iio_samples *current_samples;
ad936x_iio_samples* current_samples;
ad936x_custom->pop_sample_buffer(current_buffer);
current_samples = current_buffer.get();
// I and Q samples are interleaved in buffer: IQIQIQ...
int32_t n_interleaved_iq_samples_per_channel = current_samples->n_bytes / (ad936x_custom->n_channels * 2);
if (noutput_items < n_interleaved_iq_samples_per_channel)
@@ -312,7 +344,7 @@ int ad936x_iio_source::general_work(int noutput_items,
else
{
// ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile);
auto **out = reinterpret_cast<int8_t **>(&output_items[0]);
auto** out = reinterpret_cast<int8_t**>(&output_items[0]);
uint32_t current_byte = 0;
uint32_t current_byte_in_gr = 0;
int16_t ch = 0;

View File

@@ -1,6 +1,7 @@
/*!
* \file ad936x_iio_source.h
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the
* AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
@@ -44,23 +45,23 @@ class ad936x_iio_source;
using ad936x_iio_source_sptr = gnss_shared_ptr<ad936x_iio_source>;
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string &pluto_uri_,
const std::string &board_type_,
int64_t bandwidth_,
int64_t sample_rate_,
int64_t freq_,
const std::string &rf_port_select_,
const std::string &rf_filter,
const std::string &gain_mode_rx0_,
const std::string &gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
int64_t freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
const std::string &fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
@@ -90,23 +91,23 @@ public:
private:
friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string &pluto_uri_,
const std::string &board_type_,
int64_t bandwidth_,
int64_t sample_rate_,
int64_t freq_,
const std::string &rf_port_select_,
const std::string &rf_filter,
const std::string &gain_mode_rx0_,
const std::string &gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
int64_t freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
const std::string &fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
@@ -116,23 +117,23 @@ private:
int tx_lo_channel_);
ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string &pluto_uri_,
const std::string &board_type_,
int64_t bandwidth_,
int64_t sample_rate_,
int64_t freq_,
const std::string &rf_port_select_,
const std::string &rf_filter,
const std::string &gain_mode_rx0_,
const std::string &gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
int64_t freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
const std::string &fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
@@ -141,7 +142,6 @@ private:
bool high_side_lo_,
int tx_lo_channel_);
void ad9361_channel_demux_to_buffer(ad936x_iio_samples *samples_in, int nchannels, gr_vector_void_star &output_items);
void ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector<std::fstream> *files_out);

View File

@@ -16,7 +16,12 @@
*/
#include "fifo_reader.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
// initial construction; pass to private constructor
FifoReader::sptr FifoReader::make(const std::string &file_name, const std::string &sample_type)

View File

@@ -84,9 +84,7 @@ private:
boost::thread *d_pcap_thread;
// boost::mutex d_mutex;
struct sockaddr_in si_me
{
};
struct sockaddr_in si_me{};
std::string d_src_device;
std::string d_origin_address;
pcap_t *descr; // ethernet pcap device descriptor

View File

@@ -0,0 +1,202 @@
/*!
* \file ion_gsms.cc
* \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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 "ion_gsms.h"
#include "gnuradio/block.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
IONGSMSFileSource::IONGSMSFileSource(
const fs::path& metadata_filepath,
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids)
: gr::sync_block(
"ion_gsms_file_source",
gr::io_signature::make(0, 0, 0),
make_output_signature(block, stream_ids)),
file_stream_(metadata_filepath.parent_path() / file.Url().Value(), std::ios::in | std::ios::binary),
io_buffer_offset_(0),
maximum_item_rate_(0),
chunk_cycle_length_(0)
{
fs::path data_filepath = metadata_filepath.parent_path() / file.Url().Value();
std::size_t block_offset = file.Offset();
if (!file_stream_.is_open())
{
LOG(WARNING) << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str();
std::cerr << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str() << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
// Skip offset and block header
file_stream_.seekg(file.Offset() + block_offset + block.SizeHeader());
std::size_t output_stream_offset = 0;
for (const auto& chunk : block.Chunks())
{
chunk_data_.emplace_back(std::make_shared<IONGSMSChunkData>(chunk, stream_ids, output_stream_offset));
chunk_cycle_length_ += chunk.CountWords() * chunk.SizeWord();
const std::size_t out_count = chunk_data_.back()->output_stream_count();
output_stream_offset += out_count;
for (std::size_t i = 0; i < out_count; ++i)
{
output_stream_item_sizes_.push_back(chunk_data_.back()->output_stream_item_size(i));
output_stream_item_rates_.push_back(chunk_data_.back()->output_stream_item_rate(i));
maximum_item_rate_ = std::max(chunk_data_.back()->output_stream_item_rate(i), maximum_item_rate_);
}
}
output_stream_count_ = output_stream_offset;
output_stream_total_sample_counts_.resize(output_stream_count_);
std::size_t cycle_count = block.Cycles();
if (cycle_count == 0)
{
// Read the whole file
const std::size_t file_size = fs::file_size(data_filepath);
cycle_count = std::floor((file_size - block_offset - block.SizeHeader()) / chunk_cycle_length_);
}
for (std::size_t i = 0; i < output_stream_count_; ++i)
{
output_stream_total_sample_counts_[i] = cycle_count * output_stream_item_rates_[i];
}
}
std::size_t IONGSMSFileSource::output_stream_count() const
{
return output_stream_count_;
}
std::size_t IONGSMSFileSource::output_stream_item_size(std::size_t stream_index) const
{
return output_stream_item_sizes_[stream_index];
}
std::size_t IONGSMSFileSource::output_stream_total_sample_count(std::size_t stream_index) const
{
return output_stream_total_sample_counts_[stream_index];
}
gr::io_signature::sptr IONGSMSFileSource::make_output_signature(const GnssMetadata::Block& block, const std::vector<std::string>& stream_ids)
{
int nstreams = 0;
std::vector<int> item_sizes{};
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
++nstreams;
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization())
{
// Samples have 'Complex' format
sample_bitsize /= 2;
}
item_sizes.push_back(bits_to_item_size(sample_bitsize));
}
}
}
}
return gr::io_signature::makev(
nstreams,
nstreams,
item_sizes);
}
int IONGSMSFileSource::work(
int noutput_items,
gr_vector_const_void_star& input_items __attribute__((unused)),
gr_vector_void_star& output_items)
{
// Compute the maximum number of samples that will be copied across all output buffer.
// If there are more than one output buffer (multichannel set up), the one with the most samples will be used as the maximum.
//
// Complex samples produce 2 items each (I and Q). In order to account for them, we subtract 1 from `noutput_items` and
// then floor the division. During testing, not doing this caused `max_sample_output` to oscillate between two values, thus
// resizing the `io_buffer_` on each call to `work()`.
const std::size_t max_sample_output = std::floor((noutput_items - 1.0) / maximum_item_rate_);
// Resize the IO buffer to fit exactly the maximum amount of samples that will be outputted.
io_buffer_.resize(max_sample_output * chunk_cycle_length_);
// We will be walking the IO buffer with this variable.
io_buffer_offset_ = 0;
// Read samples from file into IO buffer
const std::size_t bytes_to_read = io_buffer_.size();
file_stream_.read(io_buffer_.data(), bytes_to_read);
// Reset `items_produced_` vector. This vector will accumulate the amount of items produced for each output stream.
items_produced_.clear();
items_produced_.resize(output_items.size());
// Walk the IO buffer one chunk cycle at a time. See ION documentation for a definition of chunk and chunk cycle.
while (io_buffer_offset_ < bytes_to_read)
{
// Iterate chunks within a chunk cycle
for (auto& chunk : chunk_data_)
{
// Copy chunk into a separate buffer where the samples will be shifted from.
const std::size_t bytes_copied = chunk->read_from_buffer(reinterpret_cast<uint8_t*>(io_buffer_.data()), io_buffer_offset_);
// Advance IO buffer offset
io_buffer_offset_ += bytes_copied;
// Shift samples into output buffers following the appropriate unpacking strategy for this chunk.
chunk->write_to_output(output_items, items_produced_);
}
}
// Call `produce(int, int)` with the appropriate item count for each output stream.
for (std::size_t i = 0; i < items_produced_.size(); ++i)
{
produce(i, items_produced_[i]);
}
return WORK_CALLED_PRODUCE;
}

View File

@@ -0,0 +1,74 @@
/*!
* \file ion_gsms.h
* \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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_ION_GSMS_H
#define GNSS_SDR_ION_GSMS_H
#include "gnss_block_interface.h"
#include "gnss_sdr_filesystem.h"
#include "ion_gsms_chunk_data.h"
#include <gnuradio/block.h>
#include <gnuradio/sync_block.h>
#include <cstddef>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class IONGSMSFileSource : public gr::sync_block
{
public:
using sptr = gnss_shared_ptr<IONGSMSFileSource>;
IONGSMSFileSource(
const fs::path& metadata_filepath,
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids);
int work(
int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items) override;
std::size_t output_stream_count() const;
std::size_t output_stream_item_size(std::size_t stream_index) const;
std::size_t output_stream_total_sample_count(std::size_t stream_index) const;
private:
static gr::io_signature::sptr make_output_signature(const GnssMetadata::Block& block, const std::vector<std::string>& stream_ids);
std::ifstream file_stream_;
std::vector<char> io_buffer_;
std::size_t io_buffer_offset_;
std::vector<int> items_produced_;
std::size_t output_stream_count_;
std::vector<std::size_t> output_stream_item_sizes_;
std::vector<std::size_t> output_stream_item_rates_;
std::vector<std::size_t> output_stream_total_sample_counts_;
std::size_t maximum_item_rate_;
std::vector<std::shared_ptr<IONGSMSChunkData>> chunk_data_;
std::size_t chunk_cycle_length_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_H

View File

@@ -20,9 +20,13 @@
#include "rtl_tcp_commands.h"
#include <boost/bind/bind.hpp>
#include <boost/thread/thread.hpp>
#include <glog/logging.h>
#include <map>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
namespace ip = boost::asio::ip;
@@ -64,9 +68,11 @@ rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address,
{
lookup_[i] = (static_cast<float>(i & 0xff) - 127.4F) * (1.0F / 128.0F);
}
// 2. Set socket options
#if BOOST_ASIO_USE_FROM_STRING
ip::address addr = ip::address::from_string(address, ec);
#else
ip::address addr = ip::make_address(address, ec);
#endif
if (ec)
{
std::cout << address << " is not an IP address\n";
@@ -74,20 +80,22 @@ rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address,
return;
}
ip::tcp::endpoint ep(addr, port);
socket_.open(ep.protocol(), ec);
// 2. Set socket options
socket_.open(ep.protocol(), ec); // NOLINT(bugprone-unused-return-value)
if (ec)
{
std::cout << "Failed to open socket.\n";
LOG(ERROR) << "Failed to open socket.";
}
socket_.set_option(boost::asio::socket_base::reuse_address(true), ec);
socket_.set_option(boost::asio::socket_base::reuse_address(true), ec); // NOLINT(bugprone-unused-return-value)
if (ec)
{
std::cout << "Failed to set reuse address option: " << ec << '\n';
LOG(WARNING) << "Failed to set reuse address option";
}
socket_.set_option(boost::asio::socket_base::linger(true, 0), ec);
socket_.set_option(boost::asio::socket_base::linger(true, 0), ec); // NOLINT(bugprone-unused-return-value)
if (ec)
{
std::cout << "Failed to set linger option: " << ec << '\n';
@@ -95,8 +103,7 @@ rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address,
}
// 3. Connect socket
socket_.connect(ep, ec);
socket_.connect(ep, ec); // NOLINT(bugprone-unused-return-value)
if (ec)
{
std::cout << "Failed to connect to " << addr << ":" << port
@@ -109,7 +116,7 @@ rtl_tcp_signal_source_c::rtl_tcp_signal_source_c(const std::string &address,
LOG(INFO) << "Connected to " << addr << ":" << port;
// 4. Set nodelay
socket_.set_option(ip::tcp::no_delay(true), ec);
socket_.set_option(ip::tcp::no_delay(true), ec); // NOLINT(bugprone-unused-return-value)
if (ec)
{
std::cout << "Failed to set no delay option.\n";
@@ -312,7 +319,7 @@ void rtl_tcp_signal_source_c::handle_read(const boost::system::error_code &ec,
unread_++;
}
}
// let woker know that more data is available
// let worker know that more data is available
not_empty_.notify_one();
// Read some more
#if USE_BOOST_BIND_PLACEHOLDERS

View File

@@ -6,7 +6,7 @@
* The implementation of this block is a combination of various helpful
* sources. The data format and command structure is taken from the
* original Osmocom rtl_tcp_source_f (https://git.osmocom.org/gr-osmosdr).
* The aynchronous reading code comes from the examples provides
* The asynchronous reading code comes from the examples provides
* by Boost.Asio and the bounded buffer producer-consumer solution is
* taken from the Boost.CircularBuffer examples (https://www.boost.org/).
*

View File

@@ -7,33 +7,49 @@
set(OPT_SIGNAL_SOURCE_LIB_SOURCES "")
set(OPT_SIGNAL_SOURCE_LIB_HEADERS "")
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad9361_manager.h)
endif()
if(ENABLE_FPGA OR ENABLE_AD9361)
if(ENABLE_MAX2771)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_spidev.h)
endif()
if(ENABLE_FPGA)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
endif()
if(ENABLE_DMA_PROXY)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h)
endif()
if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} pps_samplestamp.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h)
if((ENABLE_FPGA AND ENABLE_AD9361) OR ENABLE_MAX2771)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
endif()
if(ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad936x_iio_samples.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad936x_iio_custom.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} pps_samplestamp.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ppstcprx.h)
endif()
if(ENABLE_ION)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms_chunk_data.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_data.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_stream_encodings.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_unpacking_ctx.h)
endif()
set(SIGNAL_SOURCE_LIB_SOURCES
rtl_tcp_commands.cc
@@ -74,11 +90,16 @@ target_link_libraries(signal_source_libs
Boost::headers
Gnuradio::runtime
PRIVATE
Gflags::gflags
Glog::glog
core_libs
)
if(ENABLE_GLOG_AND_GFLAGS)
target_link_libraries(signal_source_libs PRIVATE Gflags::gflags Glog::glog)
target_compile_definitions(signal_source_libs PRIVATE -DUSE_GLOG_AND_GFLAGS=1)
else()
target_link_libraries(signal_source_libs PRIVATE absl::flags absl::log)
endif()
target_include_directories(signal_source_libs
PUBLIC
${GNSSSDR_SOURCE_DIR}/src/core/receiver
@@ -92,7 +113,7 @@ if(GNURADIO_USES_STD_POINTERS)
)
endif()
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR)
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR)
target_link_libraries(signal_source_libs
PUBLIC
Iio::iio
@@ -115,6 +136,10 @@ if(ENABLE_FPGA OR ENABLE_AD9361)
)
endif()
if(ENABLE_ION)
target_link_libraries(signal_source_libs PUBLIC ION::ion algorithms_libs)
endif()
if(ENABLE_CLANG_TIDY)
if(CLANG_TIDY_EXE)
set_target_properties(signal_source_libs

View File

@@ -16,7 +16,6 @@
* -----------------------------------------------------------------------------
*/
#include "ad9361_manager.h"
#include <glog/logging.h>
#include <ad9361.h>
#include <cmath>
#include <fstream> // for ifstream
@@ -25,6 +24,12 @@
#include <utility>
#include <vector>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
/* check return value of attr_write function */
void errchk(int v, const char *what)
{
@@ -344,7 +349,7 @@ bool config_ad9361_rx_local(uint64_t bandwidth_,
#ifndef LIBAD9361_VERSION_GREATER_THAN_01
if (filter_source_ == "Design")
{
std::cout << "Option filter_source=Design is not available in this version. Set to filter_source=Off\n";
std::cout << "Option filter_source=Design is not available in this version of libad9361. Set to filter_source=Off\n";
filter_source_ = std::string("Off");
}
if (Fpass_ != 0.0 or Fstop_ != 0.0)
@@ -631,7 +636,7 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
{
return false;
}
if (setup_filter(std::move(filter_source_), bandwidth_, sample_rate_, freq_, rf_port_select_, ad9361_phy, rx_chan0, chn, 0, std::move(filter_filename_), Fpass_, Fstop_) == -1)
if (setup_filter(filter_source_, bandwidth_, sample_rate_, freq_, rf_port_select_, ad9361_phy, rx_chan0, chn, 0, std::move(filter_filename_), Fpass_, Fstop_) == -1)
{
return false;
}

View File

@@ -1,6 +1,7 @@
/*!
* \file ad936x_iio_custom.cc
* \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities.
* \brief A direct IIO custom front-end driver for the AD936x AD front-end
* family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
@@ -13,9 +14,9 @@
* -----------------------------------------------------------------------------
*/
#include "ad936x_iio_custom.h"
#include "display.h"
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <glog/logging.h>
#include <chrono>
#include <cmath>
#include <fstream>
@@ -24,28 +25,42 @@
#include <utility>
#include <vector>
ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_)
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
ad936x_iio_custom::ad936x_iio_custom(
int debug_level_,
int log_level_) : n_channels(0),
ctx(nullptr),
phy(nullptr),
stream_dev(nullptr),
dds_dev(nullptr),
receive_samples(false),
fpga_overflow(false),
sample_rate_sps(0),
debug_level(debug_level_),
log_level(log_level_),
PPS_mode(false)
{
receive_samples = false;
fpga_overflow = false;
sample_rate_sps = 0;
ctx = NULL;
phy = NULL;
dds_dev = NULL;
stream_dev = NULL;
debug_level = debug_level_;
log_level = log_level_;
PPS_mode = false;
n_channels = 0;
}
ad936x_iio_custom::~ad936x_iio_custom()
{
// disable TX
if (phy != NULL) PlutoTxEnable(false);
if (phy != nullptr)
{
PlutoTxEnable(false);
}
// Close device
if (ctx != NULL) iio_context_destroy(ctx);
if (ctx != nullptr)
{
iio_context_destroy(ctx);
}
}
@@ -54,12 +69,14 @@ void ad936x_iio_custom::set_gnsstime_queue(std::shared_ptr<Concurrent_Queue<Gnss
GnssTime_queue = std::move(queue);
}
void ad936x_iio_custom::set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue)
{
Pps_queue = std::move(queue);
}
bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::string board_type)
bool ad936x_iio_custom::initialize_device(const std::string &pluto_device_uri, const std::string &board_type)
{
// Find devices
if (pluto_device_uri == "local")
@@ -114,25 +131,24 @@ bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::str
ctx = iio_create_context_from_uri(pluto_device_uri.c_str());
}
if (ctx == NULL)
if (ctx == nullptr)
{
std::cout << "Unable to create context from uri: " << pluto_device_uri << std::endl;
return false;
}
phy = iio_context_find_device(ctx, "ad9361-phy");
if (phy == NULL)
if (phy == nullptr)
{
std::cout << "Unable to find ad9361-phy device from uri: " << pluto_device_uri << std::endl;
return false;
}
if (board_type.compare("fmcomms5") == 0)
if (board_type == "fmcomms5")
{
stream_dev = iio_context_find_device(ctx, "cf-ad9361-A"); // first ad9361 in FMCOMMS5
if (stream_dev == NULL)
if (stream_dev == nullptr)
{
std::cout << "Unable to find cf-ad9361-A device from uri: " << pluto_device_uri << std::endl;
return false;
@@ -141,13 +157,13 @@ bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::str
else
{
stream_dev = iio_context_find_device(ctx, "cf-ad9361-lpc"); // regular AD9361 stream device in single AD9361 boards
if (stream_dev == NULL)
if (stream_dev == nullptr)
{
std::cout << "Unable to find cf-ad9361-lpc device from uri: " << pluto_device_uri << std::endl;
return false;
};
dds_dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); // DDS core for LO oscillator (external transverter operation)
if (stream_dev == NULL)
if (stream_dev == nullptr)
{
std::cout << "Warning: Unable to find cf-ad9361-dds-core-lpc device from uri: " << pluto_device_uri << std::endl;
};
@@ -160,23 +176,22 @@ bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::str
void ad936x_iio_custom::configure_params(struct iio_device *phy,
const std::vector<std::string> &params)
{
for (std::vector<std::string>::const_iterator it = params.begin();
it != params.end(); ++it)
for (const auto &param : params)
{
struct iio_channel *chn = NULL;
const char *attr = NULL;
struct iio_channel *chn = nullptr;
const char *attr = nullptr;
size_t pos;
int ret;
pos = it->find('=');
pos = param.find('=');
if (pos == std::string::npos)
{
std::cerr << "Malformed line: " << *it << std::endl;
std::cerr << "Malformed line: " << param << std::endl;
continue;
}
std::string key = it->substr(0, pos);
std::string val = it->substr(pos + 1, std::string::npos);
std::string key = param.substr(0, pos);
std::string val = param.substr(pos + 1, std::string::npos);
ret = iio_device_identify_filename(phy,
key.c_str(), &chn, &attr);
@@ -188,13 +203,19 @@ void ad936x_iio_custom::configure_params(struct iio_device *phy,
}
if (chn)
ret = iio_channel_attr_write(chn,
attr, val.c_str());
{
ret = iio_channel_attr_write(chn,
attr, val.c_str());
}
else if (iio_device_find_attr(phy, attr))
ret = iio_device_attr_write(phy, attr, val.c_str());
{
ret = iio_device_attr_write(phy, attr, val.c_str());
}
else
ret = iio_device_debug_attr_write(phy,
attr, val.c_str());
{
ret = iio_device_debug_attr_write(phy,
attr, val.c_str());
}
if (ret < 0)
{
std::cerr << "Unable to write attribute " << key
@@ -208,9 +229,9 @@ void ad936x_iio_custom::set_params_rx(struct iio_device *phy_device,
unsigned long long frequency,
unsigned long samplerate, unsigned long bandwidth,
bool quadrature, bool rfdc, bool bbdc,
std::string gain1, double gain1_value,
std::string gain2, double gain2_value,
std::string port_select)
const std::string &gain1, double gain1_value,
const std::string &gain2, double gain2_value,
const std::string &port_select)
{
std::vector<std::string> params;
@@ -281,7 +302,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_,
std::to_string(phase_dds_deg_ * 1000.0));
params_dds.push_back("out_altvoltage0_TX1_I_F1_scale=" +
std::to_string(scale_dds_));
params_dds.push_back("out_altvoltage0_TX1_I_F1_raw=1");
params_dds.emplace_back("out_altvoltage0_TX1_I_F1_raw=1");
// DDS TX CH1 Q (tone #1)
params_dds.push_back("out_altvoltage2_TX1_Q_F1_frequency=" +
std::to_string(freq_dds_tx_hz_));
@@ -289,7 +310,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_,
std::to_string(phase_dds_deg_ * 1000.0 + 270000.0));
params_dds.push_back("out_altvoltage2_TX1_Q_F1_scale=" +
std::to_string(scale_dds_));
params_dds.push_back("out_altvoltage2_TX1_Q_F1_raw=1");
params_dds.emplace_back("out_altvoltage2_TX1_Q_F1_raw=1");
configure_params(dds_dev, params_dds);
}
@@ -310,7 +331,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_,
std::to_string(phase_dds_deg_ * 1000.0));
params_dds.push_back("out_altvoltage4_TX2_I_F1_scale=" +
std::to_string(scale_dds_));
params_dds.push_back("out_altvoltage4_TX2_I_F1_raw=1");
params_dds.emplace_back("out_altvoltage4_TX2_I_F1_raw=1");
// DDS TX CH2 Q (tone #1)
params_dds.push_back("out_altvoltage6_TX2_Q_F1_frequency=" +
std::to_string(freq_dds_tx_hz_));
@@ -318,19 +339,18 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_,
std::to_string(phase_dds_deg_ * 1000.0 + 270000.0));
params_dds.push_back("out_altvoltage6_TX2_Q_F1_scale=" +
std::to_string(scale_dds_));
params_dds.push_back("out_altvoltage6_TX2_Q_F1_raw=1");
params_dds.emplace_back("out_altvoltage6_TX2_Q_F1_raw=1");
configure_params(dds_dev, params_dds);
}
return true;
}
bool ad936x_iio_custom::check_device()
{
if (stream_dev != NULL)
if (stream_dev != nullptr)
{
return true;
}
@@ -340,10 +360,11 @@ bool ad936x_iio_custom::check_device()
}
}
bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string &param, std::string &value)
{
struct iio_channel *chn = 0;
const char *attr = 0;
struct iio_channel *chn = nullptr;
const char *attr = nullptr;
char valuestr[256];
int ret;
ssize_t nchars;
@@ -381,6 +402,7 @@ bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string &param,
}
}
bool ad936x_iio_custom::read_die_temp(double &temp_c)
{
std::string temp_mC_str;
@@ -389,9 +411,12 @@ bool ad936x_iio_custom::read_die_temp(double &temp_c)
{
try
{
uint32_t temp_mC = boost::lexical_cast<uint32_t>(temp_mC_str);
auto temp_mC = boost::lexical_cast<uint32_t>(temp_mC_str);
temp_c = static_cast<double>(temp_mC) / 1000.0;
if (temp_c > 120) temp_c = -1;
if (temp_c > 120)
{
temp_c = -1;
}
return true;
}
catch (const boost::bad_lexical_cast &e)
@@ -405,13 +430,15 @@ bool ad936x_iio_custom::read_die_temp(double &temp_c)
return false;
}
}
bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string &rf_port_select_,
const std::string &rf_filter,
const std::string &gain_mode_rx0_,
const std::string &gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
@@ -420,18 +447,20 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_)
{
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
bool no_errors = true;
std::cout << "Configuring phy device parameters...\n";
int ret;
if (rf_filter.compare("Disabled") == 0)
if (rf_filter == "Disabled")
{
std::cout << "LNA Filter switch is disabled.\n";
}
else if (rf_filter.compare("Auto") == 0)
else if (rf_filter == "Auto")
{
std::cout << "Selecting LNA RF filter based on the selected RF frequency... \n";
if (freq_ == 1575420000)
@@ -488,9 +517,9 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
params.push_back("out_voltage_rf_bandwidth=" +
std::to_string(bandwidth_));
params.push_back("in_voltage_quadrature_tracking_en=1");
params.push_back("in_voltage_rf_dc_offset_tracking_en=1");
params.push_back("in_voltage_bb_dc_offset_tracking_en=1");
params.emplace_back("in_voltage_quadrature_tracking_en=1");
params.emplace_back("in_voltage_rf_dc_offset_tracking_en=1");
params.emplace_back("in_voltage_bb_dc_offset_tracking_en=1");
configure_params(phy, params);
@@ -605,14 +634,12 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
std::cerr << "Warning: rf_port_select write returned: " << ret << "\n";
no_errors = false;
}
// ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_);
// if (ret < 0)
// {
// std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n";
// no_errors = false;
// }
long long set_rf_bw;
ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw);
if (ret < 0)
@@ -625,7 +652,6 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n";
}
if (setRXGain(0, gain_mode_rx0_, rf_gain_rx0_) == false)
{
std::cerr << "Info: setRXGain read returned false \n";
@@ -657,14 +683,12 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
std::cerr << "Warning: rf_port_select write returned: " << ret << "\n";
no_errors = false;
}
// ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_);
// if (ret < 0)
// {
// std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n";
// no_errors = false;
// }
long long set_rf_bw;
ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw);
if (ret < 0)
@@ -697,9 +721,13 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_,
return no_errors;
}
bool ad936x_iio_custom::set_rx_frequency(long long freq_hz)
{
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
// Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator)
struct iio_channel *lo_ch;
@@ -722,7 +750,10 @@ bool ad936x_iio_custom::set_rx_frequency(long long freq_hz)
bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz)
{
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
// Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator)
struct iio_channel *lo_ch;
@@ -742,9 +773,13 @@ bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz)
return true;
}
bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain_dB)
bool ad936x_iio_custom::setRXGain(int ch_num, const std::string &gain_mode, double gain_dB)
{
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
std::vector<std::string> params;
if (ch_num == 0)
{
@@ -774,9 +809,13 @@ bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain
}
}
double ad936x_iio_custom::get_rx_gain(int ch_num)
{
if (check_device() == false) return -1;
if (check_device() == false)
{
return -1;
}
double gain_dB; // gain in dB
int ret = 0;
if (ch_num == 0)
@@ -807,11 +846,15 @@ double ad936x_iio_custom::get_rx_gain(int ch_num)
bool ad936x_iio_custom::calibrate([[maybe_unused]] int ch, [[maybe_unused]] double bw_hz)
{
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
// todo
return true;
}
void ad936x_iio_custom::monitor_thread_fn()
{
uint32_t val;
@@ -844,24 +887,27 @@ void ad936x_iio_custom::monitor_thread_fn()
// } else {
if (val & 4)
{
std::cout << "WARNING: IIO status register reported overflow!\n";
LOG(INFO) << "WARNING: IIO status register reported overflow!";
std::cout
<< TEXT_BOLD_RED
<< "WARNING: IIO status register reported overflow!\n";
LOG(WARNING) << "WARNING: IIO status register reported overflow!";
}
/* Clear bits */
if (val)
{
ret = iio_device_reg_write(stream_dev, 0x80000088, val);
if (ret)
fprintf(stderr, "Failed to clearn DMA status register: %s\n",
strerror(-ret));
{
fprintf(stderr, "Failed to clearn DMA status register: %s\n",
strerror(-ret));
}
}
sleep(1);
}
return;
}
void ad936x_iio_custom::stop_record()
{
receive_samples = false;
@@ -910,6 +956,7 @@ void ad936x_iio_custom::PlutoTxEnable(bool txon)
}
}
void ad936x_iio_custom::setPlutoGpo(int p)
{
char pins[11];
@@ -928,7 +975,7 @@ void ad936x_iio_custom::setPlutoGpo(int p)
}
bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
bool ad936x_iio_custom::select_rf_filter(const std::string &rf_filter)
{
// adi,gpo-manual-mode-enable Enables GPO manual mode, this will conflict with automatic ENSM slave and eLNA mode
// adi,gpo-manual-mode-enable-mask Enable bit mask, setting or clearing bits will change the level of the corresponding output. Bit0 → GPO, Bit1 → GPO1, Bit2 → GPO2, Bit3 → GP03
@@ -948,8 +995,10 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
// 1 Enable
// X Enable Mask if Identifier=0xF
if (check_device() == false) return false;
if (check_device() == false)
{
return false;
}
// int plutoGpo = 0;
int ret;
ret = iio_device_debug_attr_write(phy, "adi,gpo-manual-mode-enable", "1");
@@ -960,7 +1009,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
return false;
}
if (rf_filter.compare("E1") == 0)
if (rf_filter == "E1")
{
// set gpio0 to switch L1 filter
// setPlutoGpo(plutoGpo);
@@ -971,7 +1020,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
return false;
}
}
else if (rf_filter.compare("E5E6") == 0)
else if (rf_filter == "E5E6")
{
// set gpio0 to switch L5/L6 filter (GPO0)
// plutoGpo = plutoGpo | 0x10;
@@ -983,7 +1032,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
return false;
}
}
if (rf_filter.compare("none") == 0)
if (rf_filter == "none")
{
std::cout << "RF external filter not selected\n";
}
@@ -1001,6 +1050,8 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter)
return true;
}
void ad936x_iio_custom::get_PPS_timestamp()
{
GnssTime tow;
@@ -1037,7 +1088,6 @@ void ad936x_iio_custom::get_PPS_timestamp()
// record pps rise samplestamp associated to the absolute sample counter
// PPS rising edge must be associated with the corresponding uBlox time message (tx once a second)
if (GnssTime_queue->timed_wait_and_pop(tow, 2000) == false)
{
if (receive_samples == true)
@@ -1068,6 +1118,8 @@ void ad936x_iio_custom::get_PPS_timestamp()
}
}
}
bool ad936x_iio_custom::start_sample_rx(bool ppsmode)
{
// using queues of smart pointers to preallocated buffers
@@ -1093,18 +1145,18 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode)
switch (n_channels)
{
case 1:
channels.push_back("voltage0"); // Channel 0 I
channels.push_back("voltage1"); // Channel 0 Q
channels.emplace_back("voltage0"); // Channel 0 I
channels.emplace_back("voltage1"); // Channel 0 Q
break;
case 2:
channels.push_back("voltage0"); // Channel 0 I
channels.push_back("voltage1"); // Channel 0 Q
channels.push_back("voltage2"); // Channel 1 I
channels.push_back("voltage3"); // Channel 1 Q
channels.emplace_back("voltage0"); // Channel 0 I
channels.emplace_back("voltage1"); // Channel 0 Q
channels.emplace_back("voltage2"); // Channel 1 I
channels.emplace_back("voltage3"); // Channel 1 Q
break;
default:
channels.push_back("voltage0"); // Channel 0 I
channels.push_back("voltage1"); // Channel 0 Q
channels.emplace_back("voltage0"); // Channel 0 I
channels.emplace_back("voltage1"); // Channel 0 Q
}
receive_samples = true;
@@ -1113,9 +1165,7 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode)
// start sample overflow detector
overflow_monitor_thread = std::thread(&ad936x_iio_custom::monitor_thread_fn, this);
// start PPS and GNSS Time capture thread
if (ppsmode == true)
{
capture_time_thread = std::thread(&ad936x_iio_custom::get_PPS_timestamp, this);
@@ -1123,19 +1173,25 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode)
return true;
}
void ad936x_iio_custom::pop_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer)
{
used_buffers.wait_and_pop(current_buffer);
}
void ad936x_iio_custom::push_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer)
{
free_buffers.push(current_buffer);
}
void ad936x_iio_custom::capture(const std::vector<std::string> &channels)
{
if (check_device() == false) return;
if (check_device() == false)
{
return;
}
struct iio_buffer *rxbuf;
@@ -1163,16 +1219,14 @@ void ad936x_iio_custom::capture(const std::vector<std::string> &channels)
}
else
{
for (std::vector<std::string>::const_iterator it =
channels.begin();
it != channels.end(); ++it)
for (const auto &channel : channels)
{
struct iio_channel *chn =
iio_device_find_channel(stream_dev,
it->c_str(), false);
channel.c_str(), false);
if (!chn)
{
std::cerr << "Channel " << it->c_str() << " not found\n";
std::cerr << "Channel " << channel.c_str() << " not found\n";
return;
}
else
@@ -1231,7 +1285,10 @@ void ad936x_iio_custom::capture(const std::vector<std::string> &channels)
items_in_buffer = static_cast<unsigned long>(ret) / bytes_to_interleaved_iq_samples;
if (items_in_buffer == 0) return;
if (items_in_buffer == 0)
{
return;
}
current_samples->n_channels = n_channels;
current_samples->n_interleaved_iq_samples = items_in_buffer;

View File

@@ -1,6 +1,7 @@
/*!
* \file ad936x_iio_custom.h
* \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities.
* \brief A direct IIO custom front-end driver for the AD936x AD front-end
* family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
@@ -14,41 +15,41 @@
*/
#ifndef SRC_LIBS_ad936x_iio_custom_H_
#define SRC_LIBS_ad936x_iio_custom_H_
#ifndef GNSS_SDR_AD936X_IIO_CUSTOM_H
#define GNSS_SDR_AD936X_IIO_CUSTOM_H
#include "ad936x_iio_samples.h"
#include "concurrent_queue.h"
#include "gnss_time.h"
#include "pps_samplestamp.h"
#include <boost/atomic.hpp>
#include <iio.h>
#include <ad9361.h> // multichip sync and high level functions
#include <memory>
#include <string>
#ifdef __APPLE__
#include <iio/iio.h>
#else
#include <iio.h>
#endif
#include "ad936x_iio_samples.h"
#include <ad9361.h> // multichip sync and high level functions
#include <thread>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
class ad936x_iio_custom
{
public:
ad936x_iio_custom(int debug_level_, int log_level_);
virtual ~ad936x_iio_custom();
bool initialize_device(std::string pluto_device_uri, std::string board_type);
bool initialize_device(const std::string &pluto_device_uri, const std::string &board_type);
bool init_config_ad9361_rx(long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
const std::string &rf_port_select_,
const std::string &rf_filter,
const std::string &gain_mode_rx0_,
const std::string &gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
@@ -61,7 +62,7 @@ public:
bool calibrate(int ch, double bw_hz);
double get_rx_gain(int ch_num);
bool setRXGain(int ch_num, std::string gain_mode, double gain_dB);
bool setRXGain(int ch_num, const std::string &gain_mode, double gain_dB);
bool set_antenna_port(int ch, int antenna_idx);
double get_frequency(int ch);
@@ -93,9 +94,9 @@ private:
unsigned long long frequency,
unsigned long samplerate, unsigned long bandwidth,
bool quadrature, bool rfdc, bool bbdc,
std::string gain1, double gain1_value,
std::string gain2, double gain2_value,
std::string port_select);
const std::string &gain1, double gain1_value,
const std::string &gain2, double gain2_value,
const std::string &port_select);
bool config_ad9361_dds(uint64_t freq_rf_tx_hz_,
double tx_attenuation_db_,
@@ -107,7 +108,7 @@ private:
void get_PPS_timestamp();
void capture(const std::vector<std::string> &channels);
bool select_rf_filter(std::string rf_filter);
bool select_rf_filter(const std::string &rf_filter);
void monitor_thread_fn();
@@ -120,15 +121,6 @@ private:
struct iio_device *stream_dev;
struct iio_device *dds_dev;
// stream
uint64_t sample_rate_sps;
int debug_level;
int log_level;
bool PPS_mode;
std::mutex mtx;
std::condition_variable cv;
@@ -142,6 +134,14 @@ private:
std::thread capture_samples_thread;
std::thread overflow_monitor_thread;
std::thread capture_time_thread;
// stream
uint64_t sample_rate_sps;
int debug_level;
int log_level;
bool PPS_mode;
};
#endif /* SRC_LIBS_ad936x_iio_custom_H_ */
/** \} */
/** \} */
#endif // GNSS_SDR_AD936X_IIO_CUSTOM_H

View File

@@ -1,25 +0,0 @@
/*!
* \file ad936x_iio_samples.cc
* \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_iio_samples.h"
ad936x_iio_samples::ad936x_iio_samples()
{
n_bytes = 0;
n_interleaved_iq_samples = 0;
step_bytes = 0;
n_channels = 0;
}

View File

@@ -15,26 +15,32 @@
*/
#ifndef SRC_LIBS_ad936x_iio_samples_H_
#define SRC_LIBS_ad936x_iio_samples_H_
#ifndef GNSS_SDR_AD936X_IIO_SAMPLES_H
#define GNSS_SDR_AD936X_IIO_SAMPLES_H
#define IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES 32768 * 4
#define IIO_INPUTRAMFIFOSIZE 256
#include <cstdint>
#include <memory>
#include <stdint.h>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
class ad936x_iio_samples
{
public:
ad936x_iio_samples();
uint32_t n_bytes;
uint32_t n_interleaved_iq_samples;
uint16_t n_channels;
uint16_t step_bytes;
ad936x_iio_samples() = default;
uint32_t n_bytes{0};
uint32_t n_interleaved_iq_samples{0};
uint16_t n_channels{0};
uint16_t step_bytes{0};
char buffer[IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 4 * 4]; // max 16 bits samples per buffer (4 channels, 2-bytes per I + 2-bytes per Q)
};
/** \} */
/** \} */
#endif

View File

@@ -25,7 +25,7 @@
#include "fpga_buffer_monitor.h"
#include "gnss_sdr_create_directory.h"
#include "gnss_sdr_filesystem.h"
#include <glog/logging.h>
#include "uio_fpga.h"
#include <ctime> // for time, localtime
#include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <fstream> // for string, ofstream
@@ -34,8 +34,14 @@
#include <unistd.h> // for close
#include <utility> // for move
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
Fpga_buffer_monitor::Fpga_buffer_monitor(
uint32_t num_freq_bands,
bool dump,
std::string dump_filename)
@@ -45,10 +51,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
d_max_buff_occ_freq_band_1(0),
d_dump(dump)
{
// open device descriptor
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
std::string device_io_name;
// 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

View File

@@ -45,10 +45,13 @@ public:
/*!
* \brief Constructor
*/
explicit Fpga_buffer_monitor(const std::string& device_name,
uint32_t num_freq_bands,
explicit Fpga_buffer_monitor(uint32_t num_freq_bands,
bool dump,
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
@@ -61,6 +64,7 @@ public:
void check_buffer_overflow_and_monitor_buffer_status();
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 uint32_t test_register_writeval = 0x55AA;
static const uint32_t num_sapmples_per_buffer_element = 2;

View File

@@ -19,130 +19,135 @@
* -----------------------------------------------------------------------------
*/
#include "fpga_dynamic_bit_selection.h"
#include "uio_fpga.h"
#include <glog/logging.h>
#include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <iostream> // for cout
#include <sys/mman.h> // for mmap
#include <unistd.h> // for close
Fpga_dynamic_bit_selection::Fpga_dynamic_bit_selection(bool enable_rx1_band, bool enable_rx2_band)
: d_map_base_freq_band_1(nullptr),
d_map_base_freq_band_2(nullptr),
d_dev_descr_freq_band_1(0),
d_dev_descr_freq_band_2(0),
d_shift_out_bits_freq_band_1(0),
d_shift_out_bits_freq_band_2(0),
d_enable_rx1_band(enable_rx1_band),
d_enable_rx2_band(enable_rx2_band)
{
if (d_enable_rx1_band)
{
open_device(&d_map_base_freq_band_1, d_dev_descr_freq_band_1, 0);
// init bit selection corresponding to frequency band 1
d_shift_out_bits_freq_band_1 = shift_out_bits_default;
d_map_base_freq_band_1[0] = d_shift_out_bits_freq_band_1;
}
if (d_enable_rx2_band)
{
open_device(&d_map_base_freq_band_2, d_dev_descr_freq_band_2, 1);
// init bit selection corresponding to frequency band 2
d_shift_out_bits_freq_band_2 = shift_out_bits_default;
d_map_base_freq_band_2[0] = d_shift_out_bits_freq_band_2;
}
DLOG(INFO) << "Dynamic bit selection FPGA class created";
}
Fpga_dynamic_bit_selection::~Fpga_dynamic_bit_selection()
{
if (d_enable_rx1_band)
{
close_device(d_map_base_freq_band_1, d_dev_descr_freq_band_1);
}
if (d_enable_rx2_band)
{
close_device(d_map_base_freq_band_2, d_dev_descr_freq_band_2);
}
}
void Fpga_dynamic_bit_selection::bit_selection()
{
if (d_enable_rx1_band)
{
bit_selection_per_rf_band(d_map_base_freq_band_1, d_shift_out_bits_freq_band_1);
}
if (d_enable_rx2_band)
{
bit_selection_per_rf_band(d_map_base_freq_band_2, d_shift_out_bits_freq_band_2);
}
}
void Fpga_dynamic_bit_selection::open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band)
{
// find the uio device file corresponding to the dynamic bit selector 0 module.
std::string device_name;
if (find_uio_dev_file_name(device_name, dyn_bit_sel_device_name, freq_band) < 0)
{
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n';
std::cout << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n';
return;
}
// dynamic bits selection corresponding to frequency band 1
if ((d_dev_descr = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
{
LOG(WARNING) << "Cannot open deviceio" << device_name;
std::cout << "Cannot open deviceio" << device_name << std::endl;
}
*d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, d_dev_descr, 0));
if (*d_map_base == reinterpret_cast<void *>(-1))
{
LOG(WARNING) << "Cannot map the FPGA dynamic bit selection module in frequency band 1 into tracking memory";
std::cout << "Could not map dynamic bit selection memory corresponding to frequency band 1.\n";
}
}
void Fpga_dynamic_bit_selection::bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t shift_out_bits)
{
// estimated signal power
uint32_t rx_signal_power = d_map_base[1];
// dynamic bit selection
if (rx_signal_power > Power_Threshold_High)
{
if (shift_out_bits < shift_out_bit_max)
{
shift_out_bits = shift_out_bits + 1;
}
}
else if (rx_signal_power < Power_Threshold_Low)
{
if (shift_out_bits > shift_out_bits_min)
{
shift_out_bits = shift_out_bits - 1;
}
}
// update bit selection corresopnding to frequency band 1
d_map_base[0] = shift_out_bits;
}
void Fpga_dynamic_bit_selection::close_device(volatile unsigned *d_map_base, int &d_dev_descr)
{
auto *aux = const_cast<unsigned *>(d_map_base);
if (munmap(static_cast<void *>(aux), FPGA_PAGE_SIZE) == -1)
{
std::cout << "Failed to unmap memory uio\n";
}
close(d_dev_descr);
}
#include "fpga_dynamic_bit_selection.h"
#include "uio_fpga.h"
#include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <iostream> // for cout
#include <sys/mman.h> // for mmap
#include <unistd.h> // for close
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
Fpga_dynamic_bit_selection::Fpga_dynamic_bit_selection(bool enable_rx1_band, bool enable_rx2_band)
: d_map_base_freq_band_1(nullptr),
d_map_base_freq_band_2(nullptr),
d_dev_descr_freq_band_1(0),
d_dev_descr_freq_band_2(0),
d_shift_out_bits_freq_band_1(0),
d_shift_out_bits_freq_band_2(0),
d_enable_rx1_band(enable_rx1_band),
d_enable_rx2_band(enable_rx2_band)
{
if (d_enable_rx1_band)
{
open_device(&d_map_base_freq_band_1, d_dev_descr_freq_band_1, 0);
// init bit selection corresponding to frequency band 1
d_shift_out_bits_freq_band_1 = shift_out_bits_default;
d_map_base_freq_band_1[0] = d_shift_out_bits_freq_band_1;
}
if (d_enable_rx2_band)
{
open_device(&d_map_base_freq_band_2, d_dev_descr_freq_band_2, 1);
// init bit selection corresponding to frequency band 2
d_shift_out_bits_freq_band_2 = shift_out_bits_default;
d_map_base_freq_band_2[0] = d_shift_out_bits_freq_band_2;
}
DLOG(INFO) << "Dynamic bit selection FPGA class created";
}
Fpga_dynamic_bit_selection::~Fpga_dynamic_bit_selection()
{
if (d_enable_rx1_band)
{
close_device(d_map_base_freq_band_1, d_dev_descr_freq_band_1);
}
if (d_enable_rx2_band)
{
close_device(d_map_base_freq_band_2, d_dev_descr_freq_band_2);
}
}
void Fpga_dynamic_bit_selection::bit_selection()
{
if (d_enable_rx1_band)
{
bit_selection_per_rf_band(d_map_base_freq_band_1, d_shift_out_bits_freq_band_1);
}
if (d_enable_rx2_band)
{
bit_selection_per_rf_band(d_map_base_freq_band_2, d_shift_out_bits_freq_band_2);
}
}
void Fpga_dynamic_bit_selection::open_device(volatile unsigned **d_map_base, int &d_dev_descr, int freq_band)
{
// find the uio device file corresponding to the dynamic bit selector 0 module.
std::string device_name;
if (find_uio_dev_file_name(device_name, dyn_bit_sel_device_name, freq_band) < 0)
{
std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n';
std::cout << "Cannot find the FPGA uio device file corresponding to device name " << dyn_bit_sel_device_name << '\n';
return;
}
// dynamic bits selection corresponding to frequency band 1
if ((d_dev_descr = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
{
LOG(WARNING) << "Cannot open deviceio" << device_name;
std::cout << "Cannot open deviceio" << device_name << std::endl;
}
*d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, d_dev_descr, 0));
if (*d_map_base == reinterpret_cast<void *>(-1))
{
LOG(WARNING) << "Cannot map the FPGA dynamic bit selection module in frequency band 1 into tracking memory";
std::cout << "Could not map dynamic bit selection memory corresponding to frequency band 1.\n";
}
}
void Fpga_dynamic_bit_selection::bit_selection_per_rf_band(volatile unsigned *d_map_base, uint32_t shift_out_bits)
{
// estimated signal power
uint32_t rx_signal_power = d_map_base[1];
// dynamic bit selection
if (rx_signal_power > Power_Threshold_High)
{
if (shift_out_bits < shift_out_bit_max)
{
shift_out_bits = shift_out_bits + 1;
}
}
else if (rx_signal_power < Power_Threshold_Low)
{
if (shift_out_bits > shift_out_bits_min)
{
shift_out_bits = shift_out_bits - 1;
}
}
// update bit selection corresponding to frequency band 1
d_map_base[0] = shift_out_bits;
}
void Fpga_dynamic_bit_selection::close_device(volatile unsigned *d_map_base, int &d_dev_descr)
{
auto *aux = const_cast<unsigned *>(d_map_base);
if (munmap(static_cast<void *>(aux), FPGA_PAGE_SIZE) == -1)
{
std::cout << "Failed to unmap memory uio\n";
}
close(d_dev_descr);
}

View File

@@ -56,7 +56,6 @@ public:
void bit_selection(void);
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
static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC

View File

@@ -0,0 +1,131 @@
/*!
* \file fpga_spidev.cc
* \brief FPGA SPI control.
*
* -----------------------------------------------------------------------------
*
* 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 "fpga_spidev.h"
#include <cstring> // for memset()
#include <fcntl.h> // for open(), O_RDWR
#include <iostream> // for std::cerr
#include <linux/spi/spidev.h> // spidev driver
#include <sys/ioctl.h> // for ioctl()
#include <unistd.h> // for close()
int Fpga_spidev::SPI_open()
{
if ((d_fd = open(SPI_DEVICE_NAME.c_str(), O_RDWR)) < 0)
{
std::cerr << "Failed to open the " << SPI_DEVICE_NAME << " device file \n";
return -1;
}
int ret;
int32_t mode = 0;
ret = ioctl(d_fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
{
std::cerr << "can't set spi mode\n";
return -1;
}
ret = ioctl(d_fd, SPI_IOC_RD_MODE32, &mode); // le digo al spi "algo"
if (ret == -1)
{
std::cerr << "can't set spi mode\n";
return -1;
}
return 0;
}
int Fpga_spidev::write_reg32(char addr, uint32_t data)
{
uint8_t data_buffer[2];
uint8_t recv_buffer[4];
int res = 0;
struct spi_ioc_transfer xfer[2];
memset(xfer, 0, sizeof(xfer));
xfer[0].bits_per_word = 8;
xfer[0].speed_hz = SPI_SPEED;
xfer[1].bits_per_word = 8;
xfer[1].speed_hz = SPI_SPEED;
memset(&recv_buffer, 0, sizeof(recv_buffer));
memset(&data_buffer, 0, sizeof(data_buffer));
data_buffer[1] = addr << 4 | 0 << 3;
xfer[0].tx_buf = (unsigned long)data_buffer;
xfer[0].len = 2;
// Would use memcpy but 'data' is in little endian
((char*)recv_buffer)[0] = ((char*)&data)[3];
((char*)recv_buffer)[1] = ((char*)&data)[2];
((char*)recv_buffer)[2] = ((char*)&data)[1];
((char*)recv_buffer)[3] = ((char*)&data)[0];
xfer[1].tx_buf = (unsigned long)recv_buffer;
xfer[1].len = 4;
res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer);
if (res < 0)
{
std::cout << "Error sending SPI message\n";
return res;
}
return 0;
}
int Fpga_spidev::read_reg32(uint8_t addr, uint32_t* copy_to)
{
uint8_t data_buffer[2];
uint8_t recv_buffer[4];
int res;
struct spi_ioc_transfer xfer[2];
memset(xfer, 0, sizeof(xfer));
xfer[0].bits_per_word = 8;
xfer[0].speed_hz = SPI_SPEED;
xfer[1].bits_per_word = 8;
xfer[1].speed_hz = SPI_SPEED;
memset(&recv_buffer, 0, sizeof(recv_buffer));
memset(&data_buffer, 0, sizeof(data_buffer));
data_buffer[1] = addr << 4 | 1 << 3;
xfer[0].tx_buf = (unsigned long)data_buffer;
xfer[0].len = 2;
xfer[1].rx_buf = (unsigned long)recv_buffer;
xfer[1].len = 4;
res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer);
if (res < 0)
{
std::cout << "Error sending SPI message\n";
return res;
}
// the register data is received in the reverse order
uint32_t tmp_result = 0;
for (uint32_t k = 0; k < 4; ++k)
{
tmp_result = tmp_result + ((recv_buffer[3 - k]) << 8 * k);
}
*copy_to = tmp_result;
return 0;
}
int Fpga_spidev::SPI_close() const
{
return close(d_fd);
}

View File

@@ -0,0 +1,62 @@
/*!
* \file fpga_spidev.h
* \brief FPGA SPI control.
*
* -----------------------------------------------------------------------------
*
* 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_FPGA_SPIDEV_H
#define GNSS_SDR_FPGA_SPIDEV_H
#include <cstdint>
#include <string>
class Fpga_spidev
{
public:
/*!
* \brief Default constructor.
*/
Fpga_spidev() = default;
/*!
* \brief Default destructor.
*/
~Fpga_spidev() = default;
/*!
* \brief write a register through the SPI.
*/
int write_reg32(char addr, uint32_t data);
/*!
* \brief read a register through the SPI.
*/
int read_reg32(uint8_t addr, uint32_t* copy_to);
/*!
* \brief Open the SPI device driver.
*/
int SPI_open(void);
/*!
* \brief Close the SPI device driver
*/
int SPI_close(void) const;
private:
static const uint32_t SPI_SPEED = 250000;
const std::string SPI_DEVICE_NAME = std::string("/dev/spidev2.0"); // Switch UIO device name
int d_fd;
};
#endif // GNSS_SDR_FPGA_SPIDEV_H

View File

@@ -21,17 +21,31 @@
*/
#include "fpga_switch.h"
#include <glog/logging.h>
#include "uio_fpga.h"
#include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <iostream> // for cout
#include <sys/mman.h> // for mmap
#include <unistd.h> // for close
Fpga_Switch::Fpga_Switch(const std::string &device_name)
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
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,
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));

View File

@@ -42,8 +42,7 @@ public:
/*!
* \brief Constructor
*/
explicit Fpga_Switch(const std::string& device_name);
Fpga_Switch(void);
/*!
* \brief Destructor
*/
@@ -55,6 +54,7 @@ public:
void set_switch_position(int32_t switch_position);
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 uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA;
static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50;

View File

@@ -19,11 +19,16 @@
#include "gnss_sdr_valve.h"
#include "command_event.h"
#include <glog/logging.h> // for LOG
#include <gnuradio/io_signature.h> // for io_signature
#include <algorithm> // for min
#include <cstring> // for memcpy
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
Gnss_Sdr_Valve::Gnss_Sdr_Valve(size_t sizeof_stream_item,
uint64_t nitems,
Concurrent_Queue<pmt::pmt_t>* queue,

View File

@@ -0,0 +1,271 @@
/*!
* \file ion_gsms_chunk_data.cc
* \brief Holds logic for reading and decoding samples from a chunk
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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 "ion_gsms_chunk_data.h"
#include <cstring>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
IONGSMSChunkData::IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector<std::string>& stream_ids, std::size_t output_stream_offset)
: chunk_(chunk),
sizeword_(chunk_.SizeWord()),
countwords_(chunk_.CountWords())
{
// Instantiate the Allocator functor
Allocator allocator(countwords_, buffer_);
// Call with_word_type with the Allocator functor
with_word_type(sizeword_, allocator);
const std::size_t total_bitsize = sizeword_ * countwords_ * 8;
std::size_t used_bitsize = 0;
std::size_t output_streams = 0;
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
used_bitsize += stream.Packedbits();
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), output_streams + output_stream_offset);
++output_streams;
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
std::size_t sample_rate = stream.RateFactor();
if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization())
{
// Samples have 'Complex' format
sample_bitsize /= 2;
sample_rate *= 2;
}
output_stream_item_size_.push_back(bits_to_item_size(sample_bitsize));
output_stream_item_rate_.push_back(sample_rate);
}
else
{
streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), -1);
}
}
}
output_stream_count_ = output_streams;
padding_bitsize_ = total_bitsize - used_bitsize;
}
IONGSMSChunkData::~IONGSMSChunkData()
{
Deleter deleter(static_cast<void*>(buffer_));
with_word_type(sizeword_, deleter);
}
std::size_t IONGSMSChunkData::read_from_buffer(uint8_t* buffer, std::size_t offset)
{
memset(buffer_, 0, sizeword_ * countwords_);
memcpy(buffer_, &buffer[offset], sizeword_ * countwords_);
return sizeword_ * countwords_;
}
void IONGSMSChunkData::write_to_output(gr_vector_void_star& outputs, std::vector<int>& output_items)
{
switch (sizeword_)
{
case 1:
unpack_words<int8_t>(outputs, output_items);
break;
case 2:
unpack_words<int16_t>(outputs, output_items);
break;
case 4:
unpack_words<int32_t>(outputs, output_items);
break;
case 8:
unpack_words<int64_t>(outputs, output_items);
break;
default:
LOG(ERROR) << "Unknown word size (" << std::to_string(sizeword_) << "), unpacking nothing.";
break;
}
}
std::size_t IONGSMSChunkData::output_stream_count() const
{
return output_stream_count_;
}
std::size_t IONGSMSChunkData::output_stream_item_size(std::size_t stream_index) const
{
return output_stream_item_size_[stream_index];
}
std::size_t IONGSMSChunkData::output_stream_item_rate(std::size_t stream_index) const
{
return output_stream_item_rate_[stream_index];
}
template <typename WT>
void IONGSMSChunkData::unpack_words(gr_vector_void_star& outputs, std::vector<int>& output_items)
{
WT* data = static_cast<WT*>(buffer_);
// TODO - Swap endianness if needed
IONGSMSChunkUnpackingCtx<WT> ctx{
chunk_.Shift(),
data,
countwords_,
};
// Head padding
if (padding_bitsize_ > 0 && chunk_.Padding() == GnssMetadata::Chunk::Head)
{
ctx.shift_padding(padding_bitsize_);
}
// Samples
for (const auto& [lump, stream, encoding, output_index] : streams_)
{
if (output_index == -1)
{
// skip stream
ctx.shift_padding(stream.Packedbits());
}
else
{
output_items[output_index] += write_stream_samples(ctx, lump, stream, encoding, &outputs[output_index]);
}
}
}
template <typename WT>
std::size_t IONGSMSChunkData::write_stream_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
const GnssMetadata::Lump& lump,
const GnssMetadata::IonStream& stream,
const GnssMetadata::StreamEncoding stream_encoding,
void** out)
{
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
std::size_t sample_count = stream.RateFactor();
if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization())
{
// Samples have 'Complex' format
sample_bitsize /= 2;
sample_count *= 2;
}
if (sample_bitsize <= 8)
{
write_n_samples<WT, int8_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int8_t**>(out));
}
else if (sample_bitsize <= 16)
{
write_n_samples<WT, int16_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int16_t**>(out));
}
else if (sample_bitsize <= 32)
{
write_n_samples<WT, int32_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int32_t**>(out));
}
else if (sample_bitsize <= 64)
{
write_n_samples<WT, int64_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int64_t**>(out));
}
return sample_count;
}
template <typename WT, typename OT>
void IONGSMSChunkData::write_n_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
GnssMetadata::Lump::LumpShift lump_shift,
uint8_t sample_bitsize,
std::size_t sample_count,
GnssMetadata::StreamEncoding stream_encoding,
OT** out)
{
if (lump_shift == GnssMetadata::Lump::shiftRight)
{
auto* sample = static_cast<OT*>(*out);
sample += sample_count;
for (std::size_t i = 0; i < sample_count; ++i)
{
*sample = 0;
ctx.shift_sample(sample_bitsize, sample);
decode_sample(sample_bitsize, sample, stream_encoding);
--sample;
}
}
else // if (lump_shift == GnssMetadata::Lump::shiftLeft || lump_shift == GnssMetadata::Lump::shiftUndefined)
{
auto* sample = static_cast<OT*>(*out);
for (std::size_t i = 0; i < sample_count; ++i)
{
*sample = 0;
ctx.shift_sample(sample_bitsize, sample);
decode_sample(sample_bitsize, sample, stream_encoding);
++sample;
}
}
(*out) += sample_count;
}
// Static utilities
template <typename Sample>
void IONGSMSChunkData::decode_sample(const uint8_t sample_bitsize, Sample* sample, const GnssMetadata::StreamEncoding encoding)
{
// using SampleType = std::remove_pointer_t<decltype(sample)>;
switch (sample_bitsize)
{
case 2:
*sample = GnssMetadata::two_bit_look_up<Sample>[encoding][*sample];
break;
case 3:
*sample = GnssMetadata::three_bit_look_up<Sample>[encoding][*sample];
break;
case 4:
*sample = GnssMetadata::four_bit_look_up<Sample>[encoding][*sample];
break;
case 5:
*sample = GnssMetadata::five_bit_look_up<Sample>[encoding][*sample];
break;
default:
// TODO - Is this an error that can happen?
// for now we'll just do nothing, if the sample is this wide it may need no decoding
break;
}
}

View File

@@ -0,0 +1,188 @@
/*!
* \file ion_gsms_chunk_data.h
* \brief Holds logic for reading and decoding samples from a chunk
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* 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_ION_GSMS_CHUNK_DATA_H
#define GNSS_SDR_ION_GSMS_CHUNK_DATA_H
#include "ion_gsms_chunk_unpacking_ctx.h"
#include "ion_gsms_stream_encodings.h"
#include <gnuradio/block.h>
#include <GnssMetadata.h>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
inline std::size_t bits_to_item_size(std::size_t bit_count)
{
if (bit_count <= 8)
{
return 1;
}
if (bit_count <= 16)
{
return 2;
}
if (bit_count <= 32)
{
return 4;
}
if (bit_count <= 64)
{
return 8;
}
// You are asking too much of this humble processor
std::cerr << "Item size too large (" << std::to_string(bit_count) << "), returning nonsense.\n";
return 1;
}
// Define a functor that has a templated operator()
struct Allocator
{
size_t countwords_;
void*& buffer_; // Using void* to hold any type of pointer
Allocator(size_t countwords, void*& buffer)
: countwords_(countwords), buffer_(buffer) {}
template <typename WordType>
void operator()() const
{
buffer_ = new WordType[countwords_];
}
};
// Define a functor to delete the allocated memory
struct Deleter
{
void* buffer_;
explicit Deleter(void* buffer)
: buffer_(buffer) {}
template <typename WordType>
void operator()() const
{
delete[] static_cast<WordType*>(buffer_);
}
};
template <typename Callback>
void with_word_type(uint8_t word_size, Callback callback)
{
switch (word_size)
{
case 1:
callback.template operator()<int8_t>();
break;
case 2:
callback.template operator()<int16_t>();
break;
case 4:
callback.template operator()<int32_t>();
break;
case 8:
callback.template operator()<int64_t>();
break;
default:
std::cerr << "Unknown word size (" << std::to_string(word_size) << "), returning nonsense.\n";
break;
}
}
class IONGSMSChunkData
{
public:
IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector<std::string>& stream_ids, std::size_t output_stream_offset);
~IONGSMSChunkData();
IONGSMSChunkData(const IONGSMSChunkData& rhl) = delete;
IONGSMSChunkData& operator=(const IONGSMSChunkData& rhl) = delete;
IONGSMSChunkData(IONGSMSChunkData&& rhl) = delete;
IONGSMSChunkData& operator=(IONGSMSChunkData&& rhl) = delete;
std::size_t read_from_buffer(uint8_t* buffer, std::size_t offset);
void write_to_output(gr_vector_void_star& outputs, std::vector<int>& output_items);
std::size_t output_stream_count() const;
std::size_t output_stream_item_size(std::size_t stream_index) const;
std::size_t output_stream_item_rate(std::size_t stream_index) const;
private:
template <typename WT>
void unpack_words(gr_vector_void_star& outputs, std::vector<int>& output_items);
template <typename WT>
std::size_t write_stream_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
const GnssMetadata::Lump& lump,
const GnssMetadata::IonStream& stream,
GnssMetadata::StreamEncoding stream_encoding,
void** out);
template <typename WT, typename OT>
void write_n_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
GnssMetadata::Lump::LumpShift lump_shift,
uint8_t sample_bitsize,
std::size_t sample_count,
GnssMetadata::StreamEncoding stream_encoding,
OT** out);
template <typename Sample>
static void decode_sample(uint8_t sample_bitsize, Sample* sample, GnssMetadata::StreamEncoding encoding);
const GnssMetadata::Chunk& chunk_;
uint8_t sizeword_;
uint8_t countwords_;
uint8_t padding_bitsize_;
std::size_t output_stream_count_;
std::vector<std::size_t> output_stream_item_size_;
std::vector<std::size_t> output_stream_item_rate_;
struct stream_metadata_t
{
const GnssMetadata::Lump& lump;
const GnssMetadata::IonStream& stream;
GnssMetadata::StreamEncoding stream_encoding;
int output_index = -1;
stream_metadata_t(
const GnssMetadata::Lump& lump_,
const GnssMetadata::IonStream& stream_,
GnssMetadata::StreamEncoding stream_encoding_,
int output_index_ = -1) : lump(lump_),
stream(stream_),
stream_encoding(stream_encoding_),
output_index(output_index_)
{
}
};
std::vector<stream_metadata_t> streams_;
void* buffer_;
};
#endif // GNSS_SDR_ION_GSMS_CHUNK_DATA_H

View File

@@ -0,0 +1,184 @@
/*!
* \file ion_gsms_chunk_unpacking_ctx.h
* \brief Holds state and provides utilities for unpacking samples from a chunk
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* This is a template class, and thus, its member functions must be defined in the header file.
*
* -----------------------------------------------------------------------------
*
* 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_ION_GSMS_CHUNK_UNPACKING_CTX_H
#define GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H
#include <gnuradio/block.h>
#include <GnssMetadata.h>
#include <cstdint>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
template <typename WT>
struct IONGSMSChunkUnpackingCtx
{
static constexpr uint8_t word_bitsize_ = sizeof(WT) * 8;
const GnssMetadata::Chunk::WordShift word_shift_direction_;
WT* iterator_ = nullptr; // Not owned by this class, MUST NOT destroy
WT current_word_{};
uint8_t bitshift_ = 0;
IONGSMSChunkUnpackingCtx(
const GnssMetadata::Chunk::WordShift word_shift,
WT* data_buffer,
uint8_t data_buffer_word_count) : word_shift_direction_(word_shift)
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
iterator_ = data_buffer;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
iterator_ = &data_buffer[data_buffer_word_count];
}
if (iterator_)
{
advance_word(); // Initializes current_word_
}
}
void advance_word()
{
WT word = *iterator_;
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
++iterator_;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
--iterator_;
}
current_word_ = word;
}
void shift_current_word(uint8_t n)
{
if ((n % word_bitsize_) == 0)
{
for (uint8_t i = 0; i < (n / word_bitsize_); ++i)
{
advance_word();
}
return;
}
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
current_word_ <<= n;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
current_word_ >>= n;
}
bitshift_ += n;
if (bitshift_ >= word_bitsize_)
{
advance_word();
bitshift_ -= word_bitsize_;
}
}
void shift_padding(uint8_t n_bits)
{
if (n_bits == 0)
{
return;
}
if ((n_bits + (bitshift_ % word_bitsize_)) >= word_bitsize_)
{
const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_);
shift_current_word(bits_shifted);
shift_padding(n_bits - bits_shifted);
}
else
{
shift_current_word(n_bits);
}
}
template <typename OT>
void shift_sample(uint8_t sample_bitsize, OT* output, uint8_t output_bit_offset = 0)
{
if (sample_bitsize % word_bitsize_ == 0)
{
const uint8_t words_per_sample = sample_bitsize / word_bitsize_;
for (uint8_t i = 0; i < words_per_sample; ++i)
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
*output |= (current_word_ << ((words_per_sample - 1 - i) * word_bitsize_));
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
*output |= (current_word_ << (i * word_bitsize_));
// TODO - reverse bit order of sample? maybe?
}
advance_word();
}
}
else if ((sample_bitsize + (bitshift_ % word_bitsize_)) > word_bitsize_)
{
const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_);
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize_ - bits_shifted)) - 1);
*output |= ((current_word_ & mask) >> output_bit_offset);
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (bits_shifted)) - 1);
*output |= (current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
}
shift_current_word(bits_shifted);
shift_sample(sample_bitsize - bits_shifted, output, bits_shifted);
}
else
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize_ - sample_bitsize)) - 1);
OT sample = (current_word_ & mask) >> (word_bitsize_ - sample_bitsize);
*output |= (sample) >> output_bit_offset;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (sample_bitsize)) - 1);
*output |= (current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
}
shift_current_word(sample_bitsize);
}
}
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H

View File

@@ -0,0 +1,170 @@
/*!
* \file ion_gsms_stream_encodings.h
* \brief Implements look up tables for all encodings in the standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* These tables are taken from the stardard's official document.
*
* -----------------------------------------------------------------------------
*
* 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_ION_GSMS_STREAM_ENCODINGS_H
#define GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
namespace GnssMetadata
{
using StreamEncoding = unsigned char;
namespace StreamEncodings
{
constexpr unsigned char SIGN = 0;
constexpr unsigned char OB = 1;
constexpr unsigned char SM = 2;
constexpr unsigned char MS = 3;
constexpr unsigned char TC = 4;
constexpr unsigned char OG = 5;
constexpr unsigned char OBA = 6;
constexpr unsigned char SMA = 7;
constexpr unsigned char MSA = 8;
constexpr unsigned char TCA = 9;
constexpr unsigned char OGA = 10;
constexpr unsigned char FP = 11;
} // namespace StreamEncodings
inline StreamEncoding encoding_from_string(const std::string& str)
{
if (str == "SIGN")
{
return StreamEncodings::SIGN;
}
if (str == "OB")
{
return StreamEncodings::OB;
}
if (str == "SM")
{
return StreamEncodings::SM;
}
if (str == "MS")
{
return StreamEncodings::MS;
}
if (str == "TC")
{
return StreamEncodings::TC;
}
if (str == "OG")
{
return StreamEncodings::OG;
}
if (str == "OBA")
{
return StreamEncodings::OBA;
}
if (str == "SMA")
{
return StreamEncodings::SMA;
}
if (str == "MSA")
{
return StreamEncodings::MSA;
}
if (str == "TCA")
{
return StreamEncodings::TCA;
}
if (str == "OGA")
{
return StreamEncodings::OGA;
}
if (str == "FP")
{
return StreamEncodings::FP;
}
return 0;
}
template <typename T>
inline T two_bit_look_up[11][4]{
{}, // [0]
{-2, -1, 0, 1}, // [1 /*OB*/]
{0, 1, 0, -1}, // [2 /*SM*/]
{0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, -2, -1}, // [4 /*TC*/]
{-2, -1, 1, 0}, // [5 /*OG*/]
{-3, -1, 1, 3}, // [6 /*OBA*/]
{1, 3, -1, -3}, // [7 /*SMA*/]
{1, -1, 3, -3}, // [8 /*MSA*/]
{1, 3, -3, -1}, // [9 /*TCA*/]
{-3, -1, 3, 1}, // [10 /*OGA*/]
};
template <typename T>
inline T three_bit_look_up[11][8]{
{}, // [0]
{-4, -3, -2, -1, 0, 1, 2, 3}, // [1 /*OB*/]
{0, 1, 2, 3, 0, -1, -2, -3}, // [2 /*SM*/]
{0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, 2, 3, -4, -3, -2, -1}, // [4 /*TC*/]
{-4, -3, -1, -2, 3, 2, 0, 1}, // [5 /*OG*/]
{-7, -5, -3, -1, 1, 3, 5, 7}, // [6 /*OBA*/]
{1, 3, 5, 7, -1, -3, -5, -7}, // [7 /*SMA*/]
{1, -1, 3, -3, 5, -5, 7, -7}, // [8 /*MSA*/]
{1, 3, 5, 7, -7, -5, -3, -1}, // [9 /*TCA*/]
{-7, -5, -1, -3, 7, 5, 1, 3}, // [10 /*OGA*/]
};
template <typename T>
inline T four_bit_look_up[11][16]{
{}, // [0]
{-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, // [1 /*OB*/]
{0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7}, // [2 /*SM*/]
{0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}, // [4 /*TC*/]
{-8, -7, -5, -6, -1, -2, -4, -3, 7, 6, 4, 5, 0, 1, 3, 2}, // [5 /*OG*/]
{-15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15}, // [6 /*OBA*/]
{1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15}, // [7 /*SMA*/]
{1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15}, // [8 /*MSA*/]
{1, 3, 5, 7, 9, 11, 13, 15, -15, -13, -11, -9, -7, -5, -3, -1}, // [9 /*TCA*/]
{-15, -13, -9, -11, -1, -3, -7, -5, 15, 13, 9, 11, 1, 3, 7, 5}, // [10 /*OGA*/]
};
template <typename T>
inline T five_bit_look_up[11][32]{
{}, // [0]
{-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, // [1 /*OB*/]
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15}, // [2 /*SM*/]
{0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1}, // [4 /*TC*/]
{-16, -15, -13, -14, -9, -10, -12, -11, -1, -2, -4, -3, -8, -7, -5, -6, 15, 14, 12, 13, 8, 9, 11, 10, 0, 1, 3, 2, 7, 6, 4, 5}, // [5 /*OG*/]
{-31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // [6 /*OBA*/]
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -1, -3, -5, -7, -9, -11, -13, -15, -17, -19, -21, -23, -25, -27, -29, -31}, // [7 /*SMA*/]
{1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15, 17, -17, 19, -19, 21, -21, 23, -23, 25, -25, 27, -27, 29, -29, 31, -31}, // [8 /*MSA*/]
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1}, // [9 /*TCA*/]
{-31, -29, -25, -27, -17, -19, -23, -21, -1, -3, -7, -5, -15, -13, -9, -11, 31, 29, 25, 27, 17, 19, 23, 21, 1, 3, 7, 5, 15, 13, 9, 11}, // [10 /*OGA*/]
};
} // namespace GnssMetadata
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H

View File

@@ -21,7 +21,7 @@
class PpsSamplestamp
{
public:
uint64_t samplestamp = 0; // PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side
uint64_t samplestamp = 0; // PPS rising edge samples counter from the beginning of rx stream operation. Notice that it is reset to zero if sample buffer overflow is detected on the FPGA side
uint32_t overflow_reg = 0; // >0 indicates overflow situation in the FPGA RX buffer
};

View File

@@ -20,19 +20,6 @@
#include <utility>
#include <vector>
pps_tcp_rx::pps_tcp_rx()
{
// TODO Auto-generated constructor stub
is_connected = false;
clientSd = -1;
}
pps_tcp_rx::~pps_tcp_rx()
{
// TODO Auto-generated destructor stub
}
void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue)
{
@@ -40,7 +27,7 @@ void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsS
}
bool pps_tcp_rx::send_cmd(std::string cmd)
bool pps_tcp_rx::send_cmd(std::string cmd) const
{
if (is_connected == true)
{
@@ -64,7 +51,7 @@ bool pps_tcp_rx::send_cmd(std::string cmd)
}
void pps_tcp_rx::receive_pps(std::string ip_address, int port)
void pps_tcp_rx::receive_pps(const std::string &ip_address, int port)
{
// create a message buffer
char buf[1500];
@@ -117,7 +104,7 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port)
{
try
{
new_pps.samplestamp = std::strtoul(data.at(0).substr(found + 3).c_str(), NULL, 0);
new_pps.samplestamp = std::strtoul(data.at(0).substr(found + 3).c_str(), nullptr, 0);
}
catch (const std::exception &ex)
{
@@ -133,7 +120,7 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port)
{
try
{
new_pps.overflow_reg = std::stoi(data.at(1).substr(found + 2).c_str(), NULL, 0);
new_pps.overflow_reg = std::stoi(data.at(1).substr(found + 2).c_str(), nullptr, 0);
}
catch (const std::exception &ex)
{
@@ -155,7 +142,9 @@ void pps_tcp_rx::receive_pps(std::string ip_address, int port)
}
}
else
new_pps_line += c;
{
new_pps_line += c;
}
}
}
else

View File

@@ -28,15 +28,15 @@ class pps_tcp_rx
{
private:
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> Pps_queue;
int clientSd;
int clientSd{-1};
public:
volatile bool is_connected;
pps_tcp_rx();
virtual ~pps_tcp_rx();
volatile bool is_connected{false};
pps_tcp_rx() = default;
virtual ~pps_tcp_rx() = default;
void receive_pps(std::string ip_address, int port);
bool send_cmd(std::string cmd);
void receive_pps(const std::string& ip_address, int port);
bool send_cmd(std::string cmd) const;
void set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue);
};