1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-10-30 14:46:23 +00:00

Merge branch 'osnma-cesare' of https://github.com/cesaaargm/osnma into osnma-cesare

This commit is contained in:
Carles Fernandez 2024-08-16 09:49:15 +02:00
commit b9e017e189
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
45 changed files with 2833 additions and 1061 deletions

View File

@ -45,6 +45,10 @@ option(ENABLE_AD936X_SDR "Enable the use of AD936X front-ends using libiio, requ
option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF) option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF)
option(ENABLE_MAX2771 "Enable the use of MAX2771 direct to FPGA hardware, requires the spidev driver" OFF)
option(ENABLE_DMA_PROXY "Enable the use of the DMA direct to FPGA hardware, requires the DMA Proxy driver" OFF)
option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF)
option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF) option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF)
@ -3267,6 +3271,107 @@ endif()
#####################################################################
# Check signal sources related to FPGA only.
#####################################################################
if(ENABLE_MAX2771 AND NOT ENABLE_FPGA)
message(STATUS "The SPIdev driver is enabled, but the FPGA is not enabled. The FPGA is required when using the SPIdev driver.")
if(ENABLE_PACKAGING)
set(ENABLE_MAX2771 OFF)
else()
message(FATAL_ERROR "ENABLE_MAX2771 can only be set when ENABLE_FPGA is also set.")
endif()
endif()
if(ENABLE_DMA_PROXY AND NOT ENABLE_FPGA)
message(STATUS "The DMA Proxy driver is enabled, but the FPGA is not enabled. The FPGA is required when using the DMA Proxy driver.")
if(ENABLE_PACKAGING)
set(ENABLE_DMA_PROXY OFF)
else()
message(FATAL_ERROR "ENABLE_DMA_PROXY can only be set when ENABLE_FPGA is also set.")
endif()
endif()
#####################################################################
# spidev driver - OPTIONAL
# Linux kernel driver that provides user-space access to Serial
# Peripheral Interface)
#####################################################################
if(ENABLE_MAX2771)
if(DEFINED ENV{SDKTARGETSYSROOT})
set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT})
else()
set(TARGET_ROOTFS_PATH "")
endif()
find_program(STRINGS_EXECUTABLE strings)
if(NOT STRINGS_EXECUTABLE)
message(STATUS "The 'strings' command could not be found. See https://www.gnu.org/software/binutils/")
message(STATUS " You can try to install it by typing:")
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU")
if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat")
message(STATUS " sudo yum install binutils")
elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE")
message(STATUS " sudo zypper install binutils")
else()
message(STATUS " sudo apt-get install binutils")
endif()
endif()
message(FATAL_ERROR "Binutils are required to build GNSS-SDR for SoC FPGA devices using the MAX2771 option.")
endif()
set(DTB_FILE "${TARGET_ROOTFS_PATH}/boot/devicetree/system-top.dtb")
if(EXISTS "${DTB_FILE}")
message(STATUS "Found DTB file: ${DTB_FILE}")
# Run the strings command and grep for "spidev"
execute_process(
COMMAND ${STRINGS_EXECUTABLE} ${DTB_FILE}
COMMAND grep "spidev"
OUTPUT_VARIABLE GREP_OUTPUT
RESULT_VARIABLE GREP_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(GREP_RESULT EQUAL 0)
message(STATUS "Found spidev-compatible peripheral in ${DTB_FILE}.")
else()
message(STATUS "SPIdev driver not found, its installation is required.")
if(ENABLE_PACKAGING)
set(ENABLE_MAX2771 OFF)
else()
message(FATAL_ERROR "SPIdev driver is required for building gnss-sdr with -DENABLE_MAX2271=ON.")
endif()
endif()
else()
message(FATAL_ERROR "The device tree (DTB) file ${DTB_FILE} cannot be found.")
endif()
endif()
#####################################################################
# DMA Proxy driver - OPTIONAL
# Simplified and efficient interface for user-space applications
# to leverage DMA capabilities for Xilinx FPGA and SoC systems
#####################################################################
if(ENABLE_DMA_PROXY)
if(DEFINED ENV{SDKTARGETSYSROOT})
set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT})
else()
set(TARGET_ROOTFS_PATH "")
endif()
set(DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/lib/modules/5.10.0-xilinx-v2021.2/extra/dma-proxy.ko")
if(EXISTS "${DMA_PROXY_FILE}")
message(STATUS "Found dma-proxy.ko file: ${DMA_PROXY_FILE}")
else()
if(ENABLE_PACKAGING)
set(ENABLE_DMA_PROXY OFF)
else()
message(FATAL_ERROR "DMA Proxy driver is required for building gnss-sdr with -DENABLE_DMA_PROXY=ON.")
endif()
endif()
endif()
############################################## ##############################################
# TELEORBIT FLEXIBAND FRONTEND - OPTIONAL # TELEORBIT FLEXIBAND FRONTEND - OPTIONAL
############################################## ##############################################
@ -3471,6 +3576,8 @@ add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. R
add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.")
add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.")
add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_MAX2771 ENABLE_MAX2771 "Enables FPGA_MAX2771_EVKIT_Signal_Source for devices with the MAX2771 chipset. Requires the spidev driver")
add_feature_info(ENABLE_DMA_PROXY ENABLE_DMA_PROXY "Enables DMA Signal_Source. Requires the DMA Proxy driver")
add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.")
add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.")

View File

@ -21,6 +21,25 @@ All notable changes to GNSS-SDR will be documented in this file.
wideband device (HackRF/LimeSDR/USRP). Demonstration: wideband device (HackRF/LimeSDR/USRP). Demonstration:
https://www.youtube.com/watch?v=ZQs2sFchJ6w https://www.youtube.com/watch?v=ZQs2sFchJ6w
https://www.youtube.com/watch?v=HnZkKj9a-QM https://www.youtube.com/watch?v=HnZkKj9a-QM
- Add the following signal sources for use when GNSS-SDR is operating on SoC
FPGA boards (`-DENABLE_FPGA=ON`):
- `ADRV9361_Z7035_Signal_Source_FPGA`: Analog Devices ADRV9361-Z7035 board.
- `FMCOMMS5_Signal_Source_FPGA`: FMCOMMS5 analog front-end.
- `MAX2771_EVKIT_Signal_Source_FPGA`: MAX2771 evaluation kit analog front-end.
- `DMA_Signal_Source_FPGA`: FPGA DMA working in post-processing mode.
When building GNSS-SDR for the SoC FPGA, the following options can be passed
to CMake with possible values of `ON` or `OFF`, and their default value is
`OFF`:
- `-DENABLE_AD9361`: Checks if the IIO driver is installed and builds the
`ADRV9361_Z7035_Signal_Source_FPGA` and the `FMCOMMS5_Signal_Source_FPGA`
sources.
- `-DENABLE_MAX2771`: Checks if the SPIdev driver is installed and builds the
`MAX2771_EVKIT_Signal_Source_FPGA` source.
- `-DENABLE_DMA_PROXY`: Checks if the DMA proxy driver is installed for
controlling the DMA in the FPGA and enables its usage.
### Improvements in Portability: ### Improvements in Portability:

View File

@ -35,6 +35,7 @@
#include <map> // for map #include <map> // for map
#include <memory> // for shared_ptr, unique_ptr #include <memory> // for shared_ptr, unique_ptr
#include <queue> // for std::queue #include <queue> // for std::queue
#include <set> // for std::set
#include <string> // for string #include <string> // for string
#include <sys/types.h> // for key_t #include <sys/types.h> // for key_t
#include <vector> // for vector #include <vector> // for vector
@ -204,7 +205,7 @@ private:
std::map<int, Gnss_Synchro> d_gnss_observables_map; std::map<int, Gnss_Synchro> d_gnss_observables_map;
std::map<int, Gnss_Synchro> d_gnss_observables_map_t0; std::map<int, Gnss_Synchro> d_gnss_observables_map_t0;
std::map<int, Gnss_Synchro> d_gnss_observables_map_t1; std::map<int, Gnss_Synchro> d_gnss_observables_map_t1;
std::map<uint32_t, std::set<uint32_t>> d_auth_nav_data_map; std::map<uint32_t, std::set<uint32_t>> d_auth_nav_data_map;
std::queue<GnssTime> d_TimeChannelTagTimestamps; std::queue<GnssTime> d_TimeChannelTagTimestamps;

View File

@ -66,11 +66,11 @@ public:
} }
/*! /*!
* \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga" * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"; return "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA";
} }
/*! /*!

View File

@ -66,11 +66,11 @@ public:
} }
/*! /*!
* \brief Returns "Galileo_E5a_Pcps_Acquisition_Fpga" * \brief Returns "Galileo_E5a_Pcps_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "Galileo_E5a_Pcps_Acquisition_Fpga"; return "Galileo_E5a_Pcps_Acquisition_FPGA";
} }
/*! /*!

View File

@ -65,7 +65,7 @@ public:
} }
/*! /*!
* \brief Returns "Galileo_E5b_Pcps_Acquisition_Fpga" * \brief Returns "Galileo_E5b_Pcps_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {

View File

@ -67,11 +67,11 @@ public:
} }
/*! /*!
* \brief Returns "GPS_L1_CA_PCPS_Acquisition_Fpga" * \brief Returns "GPS_L1_CA_PCPS_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L1_CA_PCPS_Acquisition_Fpga"; return "GPS_L1_CA_PCPS_Acquisition_FPGA";
} }
/*! /*!

View File

@ -60,11 +60,11 @@ public:
} }
/*! /*!
* \brief Returns "GPS_L2_M_PCPS_Acquisition_Fpga" * \brief Returns "GPS_L2_M_PCPS_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L2_M_PCPS_Acquisition_Fpga"; return "GPS_L2_M_PCPS_Acquisition_FPGA";
} }
inline size_t item_size() override inline size_t item_size() override

View File

@ -69,11 +69,11 @@ public:
} }
/*! /*!
* \brief Returns "GPS_L5i_PCPS_Acquisition_Fpga" * \brief Returns "GPS_L5i_PCPS_Acquisition_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L5i_PCPS_Acquisition_Fpga"; return "GPS_L5i_PCPS_Acquisition_FPGA";
} }
/*! /*!

View File

@ -37,8 +37,26 @@ if(ENABLE_AD9361)
############################################### ###############################################
# AD9361 DIRECT TO FPGA Hardware # AD9361 DIRECT TO FPGA Hardware
############################################### ###############################################
list(APPEND OPT_DRIVER_SOURCES ad9361_fpga_signal_source.cc) list(APPEND OPT_DRIVER_SOURCES adrv9361_z7035_signal_source_fpga.cc)
list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h) 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() endif()
if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND)

View File

@ -1,885 +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 <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
#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;
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)),
#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
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"));
}
#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;
}
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

@ -0,0 +1,398 @@
/*!
* \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_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", 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)),
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)),
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_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));
}
if (filter_auto_)
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Auto"));
}
else
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Off"));
}
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";
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";
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(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
lock_buffer_monitor.unlock();
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.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 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::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex);
if (enable_dynamic_bit_selection_ == false)
{
dynamic_bit_selection_active = false;
}
lock.unlock();
}
}
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::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 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 * \file adrv9361_z7035_signal_source_fpga.h
* \brief signal source for Analog Devices front-end AD9361 connected directly * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board
* to FPGA accelerators. * directly connected to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with * This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks. * conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking * Please use the fmcomms2 source if conventional SDR acquisition and tracking
@ -12,14 +12,14 @@
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR. * 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 * SPDX-License-Identifier: GPL-3.0-or-later
* *
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H #ifndef GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H #define GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
#include "concurrent_queue.h" #include "concurrent_queue.h"
#include "fpga_buffer_monitor.h" #include "fpga_buffer_monitor.h"
@ -44,16 +44,14 @@
class ConfigurationInterface; class ConfigurationInterface;
class Ad9361FpgaSignalSource : public SignalSourceBase class Adrv9361z7035SignalSourceFPGA : public SignalSourceBase
{ {
public: public:
Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream, const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~Ad9361FpgaSignalSource(); ~Adrv9361z7035SignalSourceFPGA();
void start() override;
inline size_t item_size() override inline size_t item_size() override
{ {
@ -66,13 +64,9 @@ public:
gr::basic_block_sptr get_right_block() override; gr::basic_block_sptr get_right_block() override;
private: private:
const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
const std::string buffer_monitor_device_name = std::string("buffer_monitor"); // buffer monitor device name
const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
const std::string default_rf_port_select = std::string("A_BALANCED"); const std::string default_rf_port_select = std::string("A_BALANCED");
const std::string default_gain_mode = std::string("slow_attack"); const std::string default_gain_mode = std::string("slow_attack");
const std::string empty_string;
const double default_tx_attenuation_db = -10.0; const double default_tx_attenuation_db = -10.0;
const double default_manual_gain_rx1 = 64.0; const double default_manual_gain_rx1 = 64.0;
const double default_manual_gain_rx2 = 64.0; const double default_manual_gain_rx2 = 64.0;
@ -86,42 +80,27 @@ private:
const uint32_t buffer_monitoring_initial_delay_ms = 2000; const uint32_t buffer_monitoring_initial_delay_ms = 2000;
// sample block size when running in post-processing mode // sample block size when running in post-processing mode
const int sample_block_size = 16384; const int sample_block_size = 16384;
const int32_t switch_to_real_time_mode = 2;
void run_DMA_process(const std::string &filename0,
const std::string &filename1,
uint64_t &samples_to_skip,
size_t &item_size,
int64_t &samples,
bool &repeat,
uint32_t &dma_buff_offset_pos,
Concurrent_Queue<pmt::pmt_t> *queue);
void run_dynamic_bit_selection_process(); void run_dynamic_bit_selection_process();
void run_buffer_monitor_process(); void run_buffer_monitor_process();
std::thread thread_file_to_dma;
std::thread thread_dynamic_bit_selection; std::thread thread_dynamic_bit_selection;
std::thread thread_buffer_monitor; std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_Switch> switch_fpga; std::shared_ptr<Fpga_Switch> switch_fpga;
std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga;
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
std::shared_ptr<Fpga_DMA> dma_fpga;
std::mutex dma_mutex;
std::mutex dynamic_bit_selection_mutex; std::mutex dynamic_bit_selection_mutex;
std::mutex buffer_monitor_mutex; std::mutex buffer_monitor_mutex;
Concurrent_Queue<pmt::pmt_t> *queue_;
std::string gain_mode_rx1_; std::string gain_mode_rx1_;
std::string gain_mode_rx2_; std::string gain_mode_rx2_;
std::string rf_port_select_; std::string rf_port_select_;
std::string filter_file_; std::string filter_file_;
std::string filter_source_; std::string filter_source_;
std::string filter_filename_; std::string filter_filename_;
std::string filename0_;
std::string filename1_;
double rf_gain_rx1_; double rf_gain_rx1_;
double rf_gain_rx2_; double rf_gain_rx2_;
@ -133,19 +112,14 @@ private:
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present) uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present)
uint64_t sample_rate_; uint64_t sample_rate_;
uint64_t bandwidth_; uint64_t bandwidth_;
uint64_t samples_to_skip_;
int64_t samples_;
uint64_t freq_dds_tx_hz_; uint64_t freq_dds_tx_hz_;
uint64_t freq_rf_tx_hz_; uint64_t freq_rf_tx_hz_;
uint64_t tx_bandwidth_; uint64_t tx_bandwidth_;
float Fpass_; float Fpass_;
float Fstop_; float Fstop_;
uint32_t num_input_files_;
uint32_t dma_buff_offset_pos_;
uint32_t in_stream_; uint32_t in_stream_;
uint32_t out_stream_; uint32_t out_stream_;
int32_t switch_position_;
size_t item_size_; size_t item_size_;
@ -156,15 +130,13 @@ private:
bool bb_dc_; bool bb_dc_;
bool rx1_enable_; bool rx1_enable_;
bool rx2_enable_; bool rx2_enable_;
bool enable_DMA_;
bool enable_dynamic_bit_selection_; bool enable_dynamic_bit_selection_;
bool enable_ovf_check_buffer_monitor_active_; bool enable_ovf_check_buffer_monitor_active_;
bool dump_; bool dump_;
bool rf_shutdown_; bool rf_shutdown_;
bool repeat_;
}; };
/** \} */ /** \} */
/** \} */ /** \} */
#endif // GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H #endif // GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H

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

@ -0,0 +1,347 @@
/*!
* \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_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)),
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_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 (filter_auto_)
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Auto"));
}
else
{
filter_source_ = configuration->property(role + ".filter_source", std::string("Off"));
}
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";
if (!disable_ad9361_rx_local())
{
LOG(WARNING) << "Problem shutting down the AD9361 RX channels";
}
}
// disable buffer overflow checking and buffer monitoring
std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
lock_buffer_monitor.unlock();
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.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 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::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex);
if (enable_dynamic_bit_selection_ == false)
{
dynamic_bit_selection_active = false;
}
lock.unlock();
}
}
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::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 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,135 @@
/*!
* \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_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 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_tx_attenuation_db = -10.0;
const double default_manual_gain_rx1 = 64.0;
const double default_manual_gain_rx2 = 64.0;
const uint64_t default_bandwidth = 12500000;
// perform dynamic bit selection every 500 ms by default
const uint32_t Gain_control_period_ms = 500;
// 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;
// sample block size when running in post-processing mode
const int sample_block_size = 16384;
const int32_t switch_to_real_time_mode = 2;
void run_dynamic_bit_selection_process();
void run_buffer_monitor_process();
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::mutex dynamic_bit_selection_mutex;
std::mutex buffer_monitor_mutex;
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 filter_auto_;
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

@ -0,0 +1,467 @@
/*!
* \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)
{
std::vector<uint32_t> 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::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
lock_buffer_monitor.unlock();
if (thread_buffer_monitor.joinable())
{
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::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 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,164 @@
/*!
* \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();
std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
std::shared_ptr<Fpga_spidev> spidev_fpga;
std::mutex buffer_monitor_mutex;
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

@ -12,17 +12,27 @@ if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
endif() 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_SOURCES} 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_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_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_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_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) endif()
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
if(ENABLE_DMA_PROXY)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc) 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) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h)
endif() endif()
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) if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)

View File

@ -25,6 +25,7 @@
#include "fpga_buffer_monitor.h" #include "fpga_buffer_monitor.h"
#include "gnss_sdr_create_directory.h" #include "gnss_sdr_create_directory.h"
#include "gnss_sdr_filesystem.h" #include "gnss_sdr_filesystem.h"
#include "uio_fpga.h"
#include <ctime> // for time, localtime #include <ctime> // for time, localtime
#include <fcntl.h> // for open, O_RDWR, O_SYNC #include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <fstream> // for string, ofstream #include <fstream> // for string, ofstream
@ -40,7 +41,7 @@
#endif #endif
Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, Fpga_buffer_monitor::Fpga_buffer_monitor(
uint32_t num_freq_bands, uint32_t num_freq_bands,
bool dump, bool dump,
std::string dump_filename) std::string dump_filename)
@ -50,10 +51,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
d_max_buff_occ_freq_band_1(0), d_max_buff_occ_freq_band_1(0),
d_dump(dump) d_dump(dump)
{ {
// open device descriptor std::string device_io_name;
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
// find the uio device file corresponding to the buffer monitor
if (find_uio_dev_file_name(device_io_name, BUFFER_MONITOR_DEVICE_NAME, 0) < 0)
{ {
LOG(WARNING) << "Cannot open deviceio" << device_name; std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << BUFFER_MONITOR_DEVICE_NAME << '\n';
return;
}
// open device descriptor
if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1)
{
LOG(WARNING) << "Cannot open deviceio" << device_io_name;
} }
// device memory map // device memory map

View File

@ -45,10 +45,13 @@ public:
/*! /*!
* \brief Constructor * \brief Constructor
*/ */
explicit Fpga_buffer_monitor(const std::string& device_name, explicit Fpga_buffer_monitor(uint32_t num_freq_bands,
uint32_t num_freq_bands,
bool dump, bool dump,
std::string dump_filename); std::string dump_filename);
// explicit Fpga_buffer_monitor(const std::string& device_name,
// uint32_t num_freq_bands,
// bool dump,
// std::string dump_filename);
/*! /*!
* \brief Destructor * \brief Destructor
@ -61,6 +64,7 @@ public:
void check_buffer_overflow_and_monitor_buffer_status(); void check_buffer_overflow_and_monitor_buffer_status();
private: private:
const std::string BUFFER_MONITOR_DEVICE_NAME = std::string("buffer_monitor"); // buffer monitor device name
static const size_t FPGA_PAGE_SIZE = 0x1000; static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t test_register_writeval = 0x55AA; static const uint32_t test_register_writeval = 0x55AA;
static const uint32_t num_sapmples_per_buffer_element = 2; static const uint32_t num_sapmples_per_buffer_element = 2;

View File

@ -56,7 +56,6 @@ public:
void bit_selection(void); void bit_selection(void);
private: private:
const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
static const size_t FPGA_PAGE_SIZE = 0x1000; static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC

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,61 @@
/*!
* \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 <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,6 +21,7 @@
*/ */
#include "fpga_switch.h" #include "fpga_switch.h"
#include "uio_fpga.h"
#include <fcntl.h> // for open, O_RDWR, O_SYNC #include <fcntl.h> // for open, O_RDWR, O_SYNC
#include <iostream> // for cout #include <iostream> // for cout
#include <sys/mman.h> // for mmap #include <sys/mman.h> // for mmap
@ -32,11 +33,19 @@
#include <absl/log/log.h> #include <absl/log/log.h>
#endif #endif
Fpga_Switch::Fpga_Switch(const std::string &device_name) Fpga_Switch::Fpga_Switch(void)
{ {
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) std::string device_io_name; // Switch UIO device file
// find the uio device file corresponding to the switch.
if (find_uio_dev_file_name(device_io_name, SWITCH_DEVICE_NAME, 0) < 0)
{ {
LOG(WARNING) << "Cannot open deviceio" << device_name; std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << SWITCH_DEVICE_NAME << '\n';
return;
}
if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1)
{
LOG(WARNING) << "Cannot open deviceio" << device_io_name;
} }
d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE, d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));

View File

@ -42,8 +42,7 @@ public:
/*! /*!
* \brief Constructor * \brief Constructor
*/ */
explicit Fpga_Switch(const std::string& device_name); Fpga_Switch(void);
/*! /*!
* \brief Destructor * \brief Destructor
*/ */
@ -55,6 +54,7 @@ public:
void set_switch_position(int32_t switch_position); void set_switch_position(int32_t switch_position);
private: private:
const std::string SWITCH_DEVICE_NAME = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
static const size_t FPGA_PAGE_SIZE = 0x1000; static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA;
static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50; static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50;

View File

@ -65,11 +65,11 @@ public:
} }
/*! /*!
* \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga" * \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga"; return "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA";
} }
/*! /*!

View File

@ -59,11 +59,11 @@ public:
} }
/*! /*!
* \brief Returns "Galileo_E5a_DLL_PLL_Tracking_Fpga" * \brief Returns "Galileo_E5a_DLL_PLL_Tracking_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "Galileo_E5a_DLL_PLL_Tracking_Fpga"; return "Galileo_E5a_DLL_PLL_Tracking_FPGA";
} }
/*! /*!

View File

@ -64,11 +64,11 @@ public:
} }
/*! /*!
* \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_Fpga" * \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; return "GPS_L1_CA_DLL_PLL_Tracking_FPGA";
} }
/*! /*!

View File

@ -57,10 +57,10 @@ public:
return role_; return role_;
} }
//! Returns "GPS_L2_M_DLL_PLL_Tracking_Fpga" //! Returns "GPS_L2_M_DLL_PLL_Tracking_FPGA"
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L2_M_DLL_PLL_Tracking_Fpga"; return "GPS_L2_M_DLL_PLL_Tracking_FPGA";
} }
inline size_t item_size() override inline size_t item_size() override

View File

@ -65,11 +65,11 @@ public:
} }
/*! /*!
* \brief Returns "GPS_L5_DLL_PLL_Tracking_Fpga" * \brief Returns "GPS_L5_DLL_PLL_Tracking_FPGA"
*/ */
inline std::string implementation() override inline std::string implementation() override
{ {
return "GPS_L5_DLL_PLL_Tracking_Fpga"; return "GPS_L5_DLL_PLL_Tracking_FPGA";
} }
/*! /*!

View File

@ -330,6 +330,28 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
d_tesla_key_verified = false; // force the verification up to the Kroot due to chain change d_tesla_key_verified = false; // force the verification up to the Kroot due to chain change
} }
if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 3 /* CREV */ && d_GST_chain_revocation_start == 0)
{
d_flag_chain_revocation = true;
d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; // delete blocks received up to now, new chain must be received.
// d_public_key_verified = false;
d_kroot_verified = false;
d_tesla_key_verified = false;
d_GST_chain_revocation_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
LOG(INFO) << "Galileo OSNMA: Chain revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]";
std::cout << "Galileo OSNMA: Chain revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl;
}
if (d_flag_chain_revocation && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */)
{
d_flag_chain_revocation = false;
uint32_t final_GST = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
double duration_hours = (final_GST - d_GST_chain_revocation_start) / 3600.0;
LOG(INFO) << "Galileo OSNMA: Chain revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"
<< ", Duration=" << duration_hours << "h";
std::cout << "Galileo OSNMA: Chain revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"
<< ", Duration=" << duration_hours << "h" << std::endl;
}
read_dsm_header(osnma_msg->hkroot[1]); read_dsm_header(osnma_msg->hkroot[1]);
read_dsm_block(osnma_msg); read_dsm_block(osnma_msg);
process_dsm_block(osnma_msg); // will process dsm block if received a complete one, then will call mack processing upon re-setting the dsm block to 0 process_dsm_block(osnma_msg); // will process dsm block if received a complete one, then will call mack processing upon re-setting the dsm block to 0
@ -2004,7 +2026,7 @@ void osnma_msg_receiver::send_data_to_pvt(const std::vector<OSNMA_NavData>& data
{ {
if (!data.empty()) if (!data.empty())
{ {
for (auto& i : data) for (const auto& i : data)
{ {
const auto tmp_obj = std::make_shared<OSNMA_NavData>(i); const auto tmp_obj = std::make_shared<OSNMA_NavData>(i);
this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj));

View File

@ -61,11 +61,11 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath,
class osnma_msg_receiver : public gr::block class osnma_msg_receiver : public gr::block
{ {
public: public:
~osnma_msg_receiver() = default; //!< Default destructor ~osnma_msg_receiver() = default; //!< Default destructor
void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes
void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes
bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes
void set_merkle_root(const std::vector<uint8_t>& v); //!< Public for benchmarking purposes void set_merkle_root(const std::vector<uint8_t>& v); //!< Public for benchmarking purposes
private: private:
friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode); friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode);
@ -130,6 +130,7 @@ private:
uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_PKREV_start{};
uint32_t d_GST_PKR_AM_start{}; uint32_t d_GST_PKR_AM_start{};
uint32_t d_GST_chain_renewal_start{}; uint32_t d_GST_chain_renewal_start{};
uint32_t d_GST_chain_revocation_start{};
uint32_t d_count_successful_tags{0}; uint32_t d_count_successful_tags{0};
uint32_t d_count_failed_tags{0}; uint32_t d_count_failed_tags{0};
@ -151,6 +152,7 @@ private:
bool d_flag_NPK_set{false}; bool d_flag_NPK_set{false};
bool d_flag_alert_message{false}; bool d_flag_alert_message{false};
bool d_flag_chain_renewal{false}; bool d_flag_chain_renewal{false};
bool d_flag_chain_revocation{false};
// Provide access to inner functions to Gtest // Provide access to inner functions to Gtest
FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification);
@ -164,6 +166,7 @@ private:
FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal);
FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation); FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation);
FRIEND_TEST(OsnmaTestVectors, ChainRenewal); FRIEND_TEST(OsnmaTestVectors, ChainRenewal);
FRIEND_TEST(OsnmaTestVectors, ChainRevocation);
FRIEND_TEST(OsnmaTestVectors, AlertMessage); FRIEND_TEST(OsnmaTestVectors, AlertMessage);
}; };

View File

@ -135,11 +135,11 @@ std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const
{ {
if (tag.ADKD == 0 || tag.ADKD == 12) if (tag.ADKD == 0 || tag.ADKD == 12)
{ {
return std::string(549, '0'); return {std::string(549, '0')};
} }
else if (tag.ADKD == 4) else if (tag.ADKD == 4)
{ {
return std::string(141, '0'); return {std::string(141, '0')};
} }
} }
auto prn_it = d_satellite_nav_data.find(tag.PRN_d); auto prn_it = d_satellite_nav_data.find(tag.PRN_d);
@ -168,8 +168,9 @@ std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const
} }
else else
{ {
for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // NOLINT(modernize-loop-convert)
{ {
// note: starts with largest (i.e. newest) navigation dataset
// Check if current key (TOW) fulfills condition // Check if current key (TOW) fulfills condition
if ((tag.TOW - 30 * tag.cop <= rev_it->first || tag.TOW - 30 * tag.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < tag.TOW) if ((tag.TOW - 30 * tag.cop <= rev_it->first || tag.TOW - 30 * tag.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < tag.TOW)
{ {
@ -269,8 +270,9 @@ bool OSNMA_NavDataManager::have_nav_data(const Tag& t) const
{ {
// iterate in reverse order to find matching TOW with Tag's COP value // iterate in reverse order to find matching TOW with Tag's COP value
std::map<uint32_t, OSNMA_NavData> tow_map = prn_it->second; std::map<uint32_t, OSNMA_NavData> tow_map = prn_it->second;
for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // NOLINT(modernize-loop-convert)
{ {
// note: starts with largest (i.e. newest) navigation dataset
// Check if current key (TOW) fulfills cut-off point and is not received after the tag // Check if current key (TOW) fulfills cut-off point and is not received after the tag
if ((t.TOW - 30 * t.cop <= rev_it->first || t.TOW - 30 * t.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < t.TOW) if ((t.TOW - 30 * t.cop <= rev_it->first || t.TOW - 30 * t.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < t.TOW)
{ {

View File

@ -98,6 +98,14 @@ if(ENABLE_AD9361)
target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1) target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1)
endif() endif()
if(ENABLE_MAX2771)
target_compile_definitions(core_receiver PRIVATE -DMAX2771_DRIVER=1)
endif()
if(ENABLE_DMA_PROXY)
target_compile_definitions(core_receiver PRIVATE -DDMA_PROXY_DRIVER=1)
endif()
if(ENABLE_OSMOSDR) if(ENABLE_OSMOSDR)
if(GROSMOSDR_FOUND) if(GROSMOSDR_FOUND)
target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1) target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1)

View File

@ -167,8 +167,17 @@
#include "fmcomms2_signal_source.h" #include "fmcomms2_signal_source.h"
#endif #endif
#if AD9361_DRIVER #if ENABLE_FPGA and AD9361_DRIVER
#include "ad9361_fpga_signal_source.h" #include "adrv9361_z7035_signal_source_fpga.h"
#include "fmcomms5_signal_source_fpga.h"
#endif
#if MAX2771_DRIVER
#include "max2771_evkit_signal_source_fpga.h"
#endif
#if DMA_PROXY_DRIVER
#include "dma_signal_source_fpga.h"
#endif #endif
#if LIMESDR_DRIVER #if LIMESDR_DRIVER
@ -812,12 +821,34 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
} }
#endif #endif
#if AD9361_DRIVER #if ENABLE_FPGA and AD9361_DRIVER
// The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver else if (implementation == "ADRV9361_Z7035_Signal_Source_FPGA")
// in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver.
else if (implementation == "Ad9361_Fpga_Signal_Source")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Ad9361FpgaSignalSource>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Adrv9361z7035SignalSourceFPGA>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
else if (implementation == "FMCOMMS5_Signal_Source_FPGA")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Fmcomms5SignalSourceFPGA>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if ENABLE_FPGA and MAX2771_DRIVER
else if (implementation == "MAX2771_EVKIT_Signal_Source_FPGA")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<MAX2771EVKITSignalSourceFPGA>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if ENABLE_FPGA and DMA_PROXY_DRIVER
else if (implementation == "DMA_Signal_Source_FPGA")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<DMASignalSourceFPGA>(configuration, role, in_streams,
out_streams, queue); out_streams, queue);
block = std::move(block_); block = std::move(block_);
} }
@ -1054,31 +1085,31 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
} }
#endif #endif
#if ENABLE_FPGA #if ENABLE_FPGA
else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
@ -1204,31 +1235,31 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
} }
#endif #endif
#if ENABLE_FPGA #if ENABLE_FPGA
else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA"))
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
@ -1492,31 +1523,31 @@ std::unique_ptr<AcquisitionInterface> GNSSBlockFactory::GetAcqBlock(
} }
#endif #endif
#if ENABLE_FPGA #if ENABLE_FPGA
else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA")
{ {
std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams,
out_streams); out_streams);
@ -1660,31 +1691,31 @@ std::unique_ptr<TrackingInterface> GNSSBlockFactory::GetTrkBlock(
} }
#endif #endif
#if ENABLE_FPGA #if ENABLE_FPGA
else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA"))
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);
block = std::move(block_); block = std::move(block_);
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams,
out_streams); out_streams);

View File

@ -582,7 +582,7 @@ int GNSSFlowgraph::connect_fpga_flowgraph()
if (src == nullptr) if (src == nullptr)
{ {
help_hint_ += " * Check implementation name for SignalSource block.\n"; help_hint_ += " * Check implementation name for SignalSource block.\n";
help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source\n"; help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Signal_Source_Fpga or Fpga_DMA_2Signal_Source\n";
return 1; return 1;
} }
if (src->item_size() == 0) if (src->item_size() == 0)

View File

@ -1,23 +1,24 @@
/*! /*!
* \file benchmark_osnma.cc * \file benchmark_osnma.cc
* \brief Benchmarks for osnma functions * \brief Benchmarks for osnma functions
* \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es * \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es
* *
* *
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
* *
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR. * This file is part of GNSS-SDR.
* *
* Copyright (C) 2024 (see AUTHORS file for a list of contributors) * Copyright (C) 2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
* *
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
#include "osnma_msg_receiver.h"
#include "Galileo_OSNMA.h" #include "Galileo_OSNMA.h"
#include "gnss_crypto.h" #include "gnss_crypto.h"
#include "osnma_helper.h" #include "osnma_helper.h"
#include "osnma_msg_receiver.h"
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include <memory> #include <memory>

View File

@ -67,7 +67,7 @@ class GalileoE1PcpsAmbiguousAcquisitionTestFpga : public ::testing::Test
{ {
public: public:
bool acquire_signal(); bool acquire_signal();
std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA";
std::vector<Gnss_Synchro> gnss_synchro_vec; std::vector<Gnss_Synchro> gnss_synchro_vec;
const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024;
@ -321,7 +321,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal()
// instantiate the FPGA switch and set the // instantiate the FPGA switch and set the
// switch position to DMA. // switch position to DMA.
std::shared_ptr<Fpga_Switch> switch_fpga; std::shared_ptr<Fpga_Switch> switch_fpga;
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(0); // set switch position to DMA switch_fpga->set_switch_position(0); // set switch position to DMA
// create the correspondign acquisition block according to the desired tracking signal // create the correspondign acquisition block according to the desired tracking signal
@ -397,7 +397,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal()
void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init() void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init()
{ {
config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("GNSS-SDR.internal_fs_sps", "4000000");
config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"); config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA");
config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.threshold", "0.00001");
config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max));
config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step));

View File

@ -66,7 +66,7 @@ class GpsL1CaPcpsAcquisitionTestFpga : public ::testing::Test
{ {
public: public:
bool acquire_signal(); bool acquire_signal();
std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA";
std::vector<Gnss_Synchro> gnss_synchro_vec; std::vector<Gnss_Synchro> gnss_synchro_vec;
const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024;
@ -320,7 +320,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal()
// instantiate the FPGA switch and set the // instantiate the FPGA switch and set the
// switch position to DMA. // switch position to DMA.
std::shared_ptr<Fpga_Switch> switch_fpga; std::shared_ptr<Fpga_Switch> switch_fpga;
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(0); // set switch position to DMA switch_fpga->set_switch_position(0); // set switch position to DMA
// create the correspondign acquisition block according to the desired tracking signal // create the correspondign acquisition block according to the desired tracking signal
@ -396,7 +396,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal()
void GpsL1CaPcpsAcquisitionTestFpga::init() void GpsL1CaPcpsAcquisitionTestFpga::init()
{ {
config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); config->set_property("GNSS-SDR.internal_fs_sps", "4000000");
config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_Fpga"); config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_FPGA");
config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.threshold", "0.00001");
config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max));
config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step));

View File

@ -638,11 +638,11 @@ bool HybridObservablesTestFpga::acquire_signal()
// instantiate the FPGA switch and set the // instantiate the FPGA switch and set the
// switch position to DMA. // switch position to DMA.
std::shared_ptr<Fpga_Switch> switch_fpga; std::shared_ptr<Fpga_Switch> switch_fpga;
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(0); // set switch position to DMA switch_fpga->set_switch_position(0); // set switch position to DMA
// create the correspondign acquisition block according to the desired tracking signal // create the correspondign acquisition block according to the desired tracking signal
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'G'; tmp_gnss_synchro.System = 'G';
signal = "1C"; signal = "1C";
@ -654,7 +654,7 @@ bool HybridObservablesTestFpga::acquire_signal()
args.freq_band = 0; // frequency band on which the DMA has to transfer the samples args.freq_band = 0; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'E'; tmp_gnss_synchro.System = 'E';
signal = "1B"; signal = "1B";
@ -666,7 +666,7 @@ bool HybridObservablesTestFpga::acquire_signal()
args.freq_band = 0; // frequency band on which the DMA has to transfer the samples args.freq_band = 0; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'E'; tmp_gnss_synchro.System = 'E';
signal = "5X"; signal = "5X";
@ -678,7 +678,7 @@ bool HybridObservablesTestFpga::acquire_signal()
args.freq_band = 1; // frequency band on which the DMA has to transfer the samples args.freq_band = 1; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'G'; tmp_gnss_synchro.System = 'G';
signal = "L5"; signal = "L5";
@ -732,19 +732,19 @@ bool HybridObservablesTestFpga::acquire_signal()
// number of samples that the DMA has to transfer // number of samples that the DMA has to transfer
unsigned int nsamples_to_transfer; unsigned int nsamples_to_transfer;
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS)));
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS)));
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS)));
} }
else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0))
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS)));
} }
@ -762,7 +762,7 @@ bool HybridObservablesTestFpga::acquire_signal()
acquisition->init(); acquisition->init();
acquisition->set_local_code(); acquisition->set_local_code();
if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA"))
{ {
// Skip the first TEST_OBS_SKIP_SAMPLES samples // Skip the first TEST_OBS_SKIP_SAMPLES samples
args.skip_used_samples = 0; args.skip_used_samples = 0;
@ -910,7 +910,7 @@ void HybridObservablesTestFpga::configure_receiver(
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
std::string System_and_Signal; std::string System_and_Signal;
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
gnss_synchro_master.System = 'G'; gnss_synchro_master.System = 'G';
std::string signal = "1C"; std::string signal = "1C";
@ -923,7 +923,7 @@ void HybridObservablesTestFpga::configure_receiver(
config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder");
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
gnss_synchro_master.System = 'E'; gnss_synchro_master.System = 'E';
std::string signal = "1B"; std::string signal = "1B";
@ -939,7 +939,7 @@ void HybridObservablesTestFpga::configure_receiver(
config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder");
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0)
{ {
gnss_synchro_master.System = 'E'; gnss_synchro_master.System = 'E';
std::string signal = "5X"; std::string signal = "5X";
@ -953,7 +953,7 @@ void HybridObservablesTestFpga::configure_receiver(
config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder");
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
gnss_synchro_master.System = 'G'; gnss_synchro_master.System = 'G';
std::string signal = "L5"; std::string signal = "L5";
@ -2031,22 +2031,22 @@ TEST_F(HybridObservablesTestFpga, ValidationOfResults)
args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR; args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR;
// reset the HW to clear the sample counters: the acquisition constructor generates a reset // reset the HW to clear the sample counters: the acquisition constructor generates a reset
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 0; args.freq_band = 0;
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 0; args.freq_band = 0;
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 1; args.freq_band = 1;
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 1; args.freq_band = 1;

View File

@ -244,6 +244,45 @@ TEST_F(OsnmaTestVectors, ChainRenewal)
ASSERT_EQ(osnma->d_count_failed_macseq, 0); ASSERT_EQ(osnma->d_count_failed_macseq, 0);
} }
TEST_F(OsnmaTestVectors, ChainRevocation)
{
// Arrange
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt";
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml";
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
std::tm input_time_step1 = {0, 45, 21, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
std::tm input_time_step2 = {0, 30, 23, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
std::tm input_time_step3 = {0, 30, 00, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
std::vector<std::tm> input_times = {input_time_step1, input_time_step2, input_time_step3};
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step1/06_OCT_2023_GST_21_45_01.csv");
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step2/06_OCT_2023_GST_23_30_01.csv");
std::vector<TestVector> testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step3/07_OCT_2023_GST_00_30_01.csv");
if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty())
{
ASSERT_TRUE(false);
}
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3};
// Act
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
ASSERT_TRUE(result);
// Assert
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
ASSERT_EQ(osnma->d_count_failed_tags, 0);
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
}
TEST_F(OsnmaTestVectors, AlertMessage) TEST_F(OsnmaTestVectors, AlertMessage)
{ {
// Arrange // Arrange

View File

@ -355,7 +355,7 @@ void GpsL1CADllPllTrackingTestFpga::configure_receiver()
std::to_string(baseband_sampling_freq)); std::to_string(baseband_sampling_freq));
// Set Tracking // Set Tracking
config->set_property("Tracking_1C.implementation", config->set_property("Tracking_1C.implementation",
"GPS_L1_CA_DLL_PLL_Tracking_Fpga"); "GPS_L1_CA_DLL_PLL_Tracking_FPGA");
config->set_property("Tracking_1C.item_type", "cshort"); config->set_property("Tracking_1C.item_type", "cshort");
config->set_property("Tracking_1C.dump", "true"); config->set_property("Tracking_1C.dump", "true");
config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_");

View File

@ -536,7 +536,7 @@ void TrackingPullInTestFpga::configure_receiver(
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
std::string System_and_Signal; std::string System_and_Signal;
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
gnss_synchro.System = 'G'; gnss_synchro.System = 'G';
std::string signal = "1C"; std::string signal = "1C";
@ -545,7 +545,7 @@ void TrackingPullInTestFpga::configure_receiver(
config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); config->set_property("Tracking.early_late_space_narrow_chips", "0.5");
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
gnss_synchro.System = 'E'; gnss_synchro.System = 'E';
std::string signal = "1B"; std::string signal = "1B";
@ -557,7 +557,7 @@ void TrackingPullInTestFpga::configure_receiver(
config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6");
config->set_property("Tracking.track_pilot", "true"); config->set_property("Tracking.track_pilot", "true");
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga")
{ {
gnss_synchro.System = 'E'; gnss_synchro.System = 'E';
std::string signal = "5X"; std::string signal = "5X";
@ -565,13 +565,13 @@ void TrackingPullInTestFpga::configure_receiver(
signal.copy(gnss_synchro.Signal, 2, 0); signal.copy(gnss_synchro.Signal, 2, 0);
if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b") if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b")
{ {
config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_Fpga")); config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_FPGA"));
} }
config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.track_pilot", "true"); config->set_property("Tracking.track_pilot", "true");
config->set_property("Tracking.order", "2"); config->set_property("Tracking.order", "2");
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
gnss_synchro.System = 'G'; gnss_synchro.System = 'G';
std::string signal = "L5"; std::string signal = "L5";
@ -634,11 +634,11 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
// instantiate the FPGA switch and set the // instantiate the FPGA switch and set the
// switch position to DMA. // switch position to DMA.
std::shared_ptr<Fpga_Switch> switch_fpga; std::shared_ptr<Fpga_Switch> switch_fpga;
switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); switch_fpga = std::make_shared<Fpga_Switch>();
switch_fpga->set_switch_position(0); // set switch position to DMA switch_fpga->set_switch_position(0); // set switch position to DMA
// create the correspondign acquisition block according to the desired tracking signal // create the correspondign acquisition block according to the desired tracking signal
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'G'; tmp_gnss_synchro.System = 'G';
signal = "1C"; signal = "1C";
@ -650,7 +650,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
args.freq_band = 0; // frequency band on which the DMA has to transfer the samples args.freq_band = 0; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'E'; tmp_gnss_synchro.System = 'E';
signal = "1B"; signal = "1B";
@ -662,7 +662,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
args.freq_band = 0; // frequency band on which the DMA has to transfer the samples args.freq_band = 0; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'E'; tmp_gnss_synchro.System = 'E';
signal = "5X"; signal = "5X";
@ -674,7 +674,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
args.freq_band = 1; // frequency band on which the DMA has to transfer the samples args.freq_band = 1; // frequency band on which the DMA has to transfer the samples
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
tmp_gnss_synchro.System = 'G'; tmp_gnss_synchro.System = 'G';
signal = "L5"; signal = "L5";
@ -732,19 +732,19 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
// number of samples that the DMA has to transfer // number of samples that the DMA has to transfer
unsigned int nsamples_to_transfer; unsigned int nsamples_to_transfer;
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS)));
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS)));
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS)));
} }
else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0))
{ {
nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS)));
} }
@ -762,7 +762,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID)
acquisition->init(); acquisition->init();
acquisition->set_local_code(); acquisition->set_local_code();
if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA"))
{ {
// Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal // Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal
// states of the downsampling filter in the FPGA // states of the downsampling filter in the FPGA
@ -1079,22 +1079,22 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults)
std::shared_ptr<AcquisitionInterface> acquisition; std::shared_ptr<AcquisitionInterface> acquisition;
// reset the HW to clear the sample counters: the acquisition constructor generates a reset // reset the HW to clear the sample counters: the acquisition constructor generates a reset
if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 0; args.freq_band = 0;
} }
else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")
{ {
acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 0; args.freq_band = 0;
} }
else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 1; args.freq_band = 1;
} }
else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")
{ {
acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0);
args.freq_band = 1; args.freq_band = 1;