diff --git a/CMakeLists.txt b/CMakeLists.txt
index 620fd5957..ffa66cf5b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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_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_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF)
@@ -3353,6 +3357,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
##############################################
@@ -3557,6 +3662,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_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_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_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.")
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index e7e594fb9..931e8988f 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -21,6 +21,25 @@ All notable changes to GNSS-SDR will be documented in this file.
wideband device (HackRF/LimeSDR/USRP). Demonstration:
https://www.youtube.com/watch?v=ZQs2sFchJ6w
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:
diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h
index 09829267c..b28d63422 100644
--- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h
@@ -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
{
- return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga";
+ return "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA";
}
/*!
diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h
index 12d38bf34..14dae0230 100644
--- a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h
@@ -66,11 +66,11 @@ public:
}
/*!
- * \brief Returns "Galileo_E5a_Pcps_Acquisition_Fpga"
+ * \brief Returns "Galileo_E5a_Pcps_Acquisition_FPGA"
*/
inline std::string implementation() override
{
- return "Galileo_E5a_Pcps_Acquisition_Fpga";
+ return "Galileo_E5a_Pcps_Acquisition_FPGA";
}
/*!
diff --git a/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h
index 8ae54e46a..d67bfd4a6 100644
--- a/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h
@@ -65,7 +65,7 @@ public:
}
/*!
- * \brief Returns "Galileo_E5b_Pcps_Acquisition_Fpga"
+ * \brief Returns "Galileo_E5b_Pcps_Acquisition_FPGA"
*/
inline std::string implementation() override
{
diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h
index cfc483cda..2b7bfd3f9 100644
--- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h
@@ -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
{
- return "GPS_L1_CA_PCPS_Acquisition_Fpga";
+ return "GPS_L1_CA_PCPS_Acquisition_FPGA";
}
/*!
diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h
index 19acec8cb..81f4d342c 100644
--- a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h
@@ -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
{
- return "GPS_L2_M_PCPS_Acquisition_Fpga";
+ return "GPS_L2_M_PCPS_Acquisition_FPGA";
}
inline size_t item_size() override
diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h
index 497ab9b90..bf2bfafcf 100644
--- a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h
+++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h
@@ -69,11 +69,11 @@ public:
}
/*!
- * \brief Returns "GPS_L5i_PCPS_Acquisition_Fpga"
+ * \brief Returns "GPS_L5i_PCPS_Acquisition_FPGA"
*/
inline std::string implementation() override
{
- return "GPS_L5i_PCPS_Acquisition_Fpga";
+ return "GPS_L5i_PCPS_Acquisition_FPGA";
}
/*!
diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt
index e4ead311b..0aa745101 100644
--- a/src/algorithms/signal_source/adapters/CMakeLists.txt
+++ b/src/algorithms/signal_source/adapters/CMakeLists.txt
@@ -37,8 +37,26 @@ if(ENABLE_AD9361)
###############################################
# AD9361 DIRECT TO FPGA Hardware
###############################################
- list(APPEND OPT_DRIVER_SOURCES ad9361_fpga_signal_source.cc)
- list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h)
+ list(APPEND OPT_DRIVER_SOURCES adrv9361_z7035_signal_source_fpga.cc)
+ list(APPEND OPT_DRIVER_HEADERS adrv9361_z7035_signal_source_fpga.h)
+ list(APPEND OPT_DRIVER_SOURCES fmcomms5_signal_source_fpga.cc)
+ list(APPEND OPT_DRIVER_HEADERS fmcomms5_signal_source_fpga.h)
+endif()
+
+if(ENABLE_MAX2771)
+ ###############################################
+ # MAX2771 EVKIT DIRECT TO FPGA Hardware
+ ###############################################
+ list(APPEND OPT_DRIVER_SOURCES max2771_evkit_signal_source_fpga.cc)
+ list(APPEND OPT_DRIVER_HEADERS max2771_evkit_signal_source_fpga.h)
+endif()
+
+if(ENABLE_DMA_PROXY)
+ ###############################################
+ # FPGA DMA source
+ ###############################################
+ list(APPEND OPT_DRIVER_SOURCES dma_signal_source_fpga.cc)
+ list(APPEND OPT_DRIVER_HEADERS dma_signal_source_fpga.h)
endif()
if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND)
diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc
deleted file mode 100644
index 3a3360bed..000000000
--- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc
+++ /dev/null
@@ -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
- * - Javier Arribas, jarribas(at)cttc.es
- *
- 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-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
-#include // for std::max
-#include // for std::chrono
-#include // for std::floor
-#include // for std::exception
-#include // for open, O_WRONLY
-#include // for std::ifstream
-#include // for std::setprecision
-#include // for std::cout
-#include // for write
-#include // fr std::vector
-
-#if USE_GLOG_AND_GFLAGS
-#include
-#else
-#include
-#include
-#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 *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(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(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(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))),
- tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast(500000))),
- Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))),
- Fstop_(configuration->property(role + ".Fstop", static_cast(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(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(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(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(size) / static_cast(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(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(size) - bytes_to_skip;
- samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(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(size) / static_cast(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(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(size) - bytes_to_skip;
- samples_rx2 = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(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(samples_) * (1 / static_cast(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(std::floor(static_cast(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(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(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(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 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 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 lock(dynamic_bit_selection_mutex);
- bool bit_selection_enabled = enable_dynamic_bit_selection_;
- lock.unlock();
-
- if (bit_selection_enabled == true)
- {
- std::unique_lock 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 *queue)
-{
- std::ifstream infile1;
- infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
-
-
- // FPGA DMA control
- dma_fpga = std::make_shared();
-
- // 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 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(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(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 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 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 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 {};
-}
diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc
new file mode 100644
index 000000000..9d29e2de2
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc
@@ -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
+ * - Javier Arribas, jarribas(at)cttc.es
+ *
- 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 "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 // for std::max
+#include // for std::chrono
+#include // for std::floor
+#include // for std::exception
+#include // for std::cout
+
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#include
+#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 *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(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(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))),
+ tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast(500000))),
+ Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))),
+ Fstop_(configuration->property(role + ".Fstop", static_cast(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(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();
+ 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(std::floor(static_cast(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(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(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(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 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 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 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 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 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 {};
+}
diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h
similarity index 70%
rename from src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h
rename to src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h
index bedd25ad5..5e7e8b7e4 100644
--- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h
+++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h
@@ -1,7 +1,7 @@
/*!
- * \file ad9361_fpga_signal_source.h
- * \brief signal source for Analog Devices front-end AD9361 connected directly
- * to FPGA accelerators.
+ * \file adrv9361_z7035_signal_source_fpga.h
+ * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board
+ * directly connected to the FPGA accelerators.
* This source implements only the AD9361 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
* Please use the fmcomms2 source if conventional SDR acquisition and tracking
@@ -12,14 +12,14 @@
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
- * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
+ * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
-#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
-#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
+#ifndef GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
+#define GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
#include "concurrent_queue.h"
#include "fpga_buffer_monitor.h"
@@ -44,16 +44,14 @@
class ConfigurationInterface;
-class Ad9361FpgaSignalSource : public SignalSourceBase
+class Adrv9361z7035SignalSourceFPGA : public SignalSourceBase
{
public:
- Ad9361FpgaSignalSource(const ConfigurationInterface *configuration,
+ Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue *queue);
- ~Ad9361FpgaSignalSource();
-
- void start() override;
+ ~Adrv9361z7035SignalSourceFPGA();
inline size_t item_size() override
{
@@ -66,13 +64,9 @@ public:
gr::basic_block_sptr get_right_block() override;
private:
- const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
- const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
- const std::string buffer_monitor_device_name = std::string("buffer_monitor"); // buffer monitor device name
const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
const std::string default_rf_port_select = std::string("A_BALANCED");
const std::string default_gain_mode = std::string("slow_attack");
- const std::string empty_string;
const double default_tx_attenuation_db = -10.0;
const double default_manual_gain_rx1 = 64.0;
const double default_manual_gain_rx2 = 64.0;
@@ -86,42 +80,27 @@ private:
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
// sample block size when running in post-processing mode
const int sample_block_size = 16384;
-
- void run_DMA_process(const std::string &filename0,
- const std::string &filename1,
- uint64_t &samples_to_skip,
- size_t &item_size,
- int64_t &samples,
- bool &repeat,
- uint32_t &dma_buff_offset_pos,
- Concurrent_Queue *queue);
+ const int32_t switch_to_real_time_mode = 2;
void run_dynamic_bit_selection_process();
void run_buffer_monitor_process();
- std::thread thread_file_to_dma;
std::thread thread_dynamic_bit_selection;
std::thread thread_buffer_monitor;
std::shared_ptr switch_fpga;
std::shared_ptr dynamic_bit_selection_fpga;
std::shared_ptr buffer_monitor_fpga;
- std::shared_ptr dma_fpga;
- std::mutex dma_mutex;
std::mutex dynamic_bit_selection_mutex;
std::mutex buffer_monitor_mutex;
- Concurrent_Queue *queue_;
-
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_;
- std::string filename0_;
- std::string filename1_;
double rf_gain_rx1_;
double rf_gain_rx2_;
@@ -133,19 +112,14 @@ private:
uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present)
uint64_t sample_rate_;
uint64_t bandwidth_;
- uint64_t samples_to_skip_;
- int64_t samples_;
uint64_t freq_dds_tx_hz_;
uint64_t freq_rf_tx_hz_;
uint64_t tx_bandwidth_;
float Fpass_;
float Fstop_;
- uint32_t num_input_files_;
- uint32_t dma_buff_offset_pos_;
uint32_t in_stream_;
uint32_t out_stream_;
- int32_t switch_position_;
size_t item_size_;
@@ -156,15 +130,13 @@ private:
bool bb_dc_;
bool rx1_enable_;
bool rx2_enable_;
- bool enable_DMA_;
bool enable_dynamic_bit_selection_;
bool enable_ovf_check_buffer_monitor_active_;
bool dump_;
bool rf_shutdown_;
- bool repeat_;
};
/** \} */
/** \} */
-#endif // GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
+#endif // GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc
new file mode 100644
index 000000000..6d4f91b03
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc
@@ -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 // for std::min
+#include // for std::chrono
+#include // for open, O_WRONLY
+#include // for std::ifstream
+#include // for std::setprecision
+#include // for std::cout
+#include // fr std::vector
+
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#include
+#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 *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(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(seconds_to_skip * sample_rate_) * 2;
+ }
+ if (header_size > 0)
+ {
+ samples_to_skip_ += header_size;
+ }
+
+ switch_fpga = std::make_shared();
+ 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(size) / static_cast(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(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(size) - bytes_to_skip;
+ samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(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(size) / static_cast(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(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(size) - bytes_to_skip;
+ samples_rx2 = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(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(samples_) * (1 / static_cast(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(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 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 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 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 *queue)
+{
+ std::ifstream infile1;
+ infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+
+
+ // FPGA DMA control
+ dma_fpga = std::make_shared();
+
+ // 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 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(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(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 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 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 {};
+}
diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h
new file mode 100644
index 000000000..efbad3b23
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+
+/** \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 *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 *queue);
+
+ void run_dynamic_bit_selection_process();
+
+ std::thread thread_file_to_dma;
+ std::thread thread_dynamic_bit_selection;
+
+ std::shared_ptr switch_fpga;
+ std::shared_ptr dynamic_bit_selection_fpga;
+ std::shared_ptr dma_fpga;
+
+ std::mutex dma_mutex;
+ std::mutex dynamic_bit_selection_mutex;
+
+ Concurrent_Queue *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
diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc
new file mode 100644
index 000000000..d8c5a65c0
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc
@@ -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
+ * - Javier Arribas, jarribas(at)cttc.es
+ *
- 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 "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 // for std::max
+#include // for std::chrono
+#include // for std::floor
+#include // for std::exception
+#include // for std::cout
+
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#include
+#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 *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(GPS_L1_FREQ_HZ))),
+ freq1_(configuration->property(role + ".freq1", static_cast(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(0.0))),
+ Fstop_(configuration->property(role + ".Fstop", static_cast(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();
+ 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(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(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 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 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 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 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 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 {};
+}
diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h
new file mode 100644
index 000000000..1bdcf4e6f
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+
+/** \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 *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 switch_fpga;
+ std::shared_ptr dynamic_bit_selection_fpga;
+ std::shared_ptr 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
diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc
new file mode 100644
index 000000000..788b50e77
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc
@@ -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 // for std::max
+#include // for std::chrono
+#include // for std::floor
+#include // for std::exception
+#include // for std::cout
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#include
+#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 *queue __attribute__((unused)))
+ : SignalSourceBase(configuration, role, "MAX2771_EVKIT_Signal_Source_FPGA"s),
+ freq_(configuration->property(role + ".freq", static_cast(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 register_values = setup_regs();
+
+ spidev_fpga = std::make_shared();
+
+ 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(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 MAX2771EVKITSignalSourceFPGA::setup_regs(void)
+{
+ std::vector register_values = std::vector(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(GPS_L1_FREQ_HZ):
+ freq_sel = 0x604;
+ break;
+ case static_cast(GPS_L2_FREQ_HZ):
+ freq_sel = 0x4B0;
+ break;
+ case static_cast(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 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 reg_read = std::vector(register_values.size());
+
+ for (uint8_t n = 0; n < register_values.size(); ++n)
+ {
+ status = spidev_fpga->read_reg32(n, ®_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 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 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 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 {};
+}
diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h
new file mode 100644
index 000000000..3008aa384
--- /dev/null
+++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h
@@ -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 // for pmt::pmt_t
+#include // for fixed-width integer types
+#include // for smart pointers
+#include // for mutex
+#include // for strings
+#include // for threads
+#include // 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 *queue);
+
+ ~MAX2771EVKITSignalSourceFPGA();
+
+ std::vector 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 register_values);
+ void run_buffer_monitor_process();
+
+
+ std::thread thread_buffer_monitor;
+
+ std::shared_ptr buffer_monitor_fpga;
+ std::shared_ptr 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
diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt
index 2b0eb6a86..3506dc4f7 100644
--- a/src/algorithms/signal_source/libs/CMakeLists.txt
+++ b/src/algorithms/signal_source/libs/CMakeLists.txt
@@ -12,17 +12,27 @@ if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
endif()
-if(ENABLE_FPGA OR ENABLE_AD9361)
+if(ENABLE_MAX2771)
+ set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc)
+ set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_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_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h)
- set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc)
- set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
+endif()
+
+if(ENABLE_DMA_PROXY)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h)
endif()
+if((ENABLE_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)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)
diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc
index 0b250d131..1f56afbf4 100644
--- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc
+++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc
@@ -25,6 +25,7 @@
#include "fpga_buffer_monitor.h"
#include "gnss_sdr_create_directory.h"
#include "gnss_sdr_filesystem.h"
+#include "uio_fpga.h"
#include // for time, localtime
#include // for open, O_RDWR, O_SYNC
#include // for string, ofstream
@@ -40,7 +41,7 @@
#endif
-Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
+Fpga_buffer_monitor::Fpga_buffer_monitor(
uint32_t num_freq_bands,
bool dump,
std::string dump_filename)
@@ -50,10 +51,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
d_max_buff_occ_freq_band_1(0),
d_dump(dump)
{
- // open device descriptor
- if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
+ std::string device_io_name;
+
+ // find the uio device file corresponding to the buffer monitor
+ if (find_uio_dev_file_name(device_io_name, BUFFER_MONITOR_DEVICE_NAME, 0) < 0)
{
- LOG(WARNING) << "Cannot open deviceio" << device_name;
+ std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << BUFFER_MONITOR_DEVICE_NAME << '\n';
+ return;
+ }
+
+ // open device descriptor
+ if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1)
+ {
+ LOG(WARNING) << "Cannot open deviceio" << device_io_name;
}
// device memory map
diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h
index 00b413e30..7231c5ae3 100644
--- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h
+++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h
@@ -45,10 +45,13 @@ public:
/*!
* \brief Constructor
*/
- explicit Fpga_buffer_monitor(const std::string& device_name,
- uint32_t num_freq_bands,
+ explicit Fpga_buffer_monitor(uint32_t num_freq_bands,
bool dump,
std::string dump_filename);
+ // explicit Fpga_buffer_monitor(const std::string& device_name,
+ // uint32_t num_freq_bands,
+ // bool dump,
+ // std::string dump_filename);
/*!
* \brief Destructor
@@ -61,6 +64,7 @@ public:
void check_buffer_overflow_and_monitor_buffer_status();
private:
+ const std::string BUFFER_MONITOR_DEVICE_NAME = std::string("buffer_monitor"); // buffer monitor device name
static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t test_register_writeval = 0x55AA;
static const uint32_t num_sapmples_per_buffer_element = 2;
diff --git a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h
index 3f4b73a5a..53729b265 100644
--- a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h
+++ b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h
@@ -56,7 +56,6 @@ public:
void bit_selection(void);
private:
- const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name
static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC
diff --git a/src/algorithms/signal_source/libs/fpga_spidev.cc b/src/algorithms/signal_source/libs/fpga_spidev.cc
new file mode 100644
index 000000000..f90cf4ac9
--- /dev/null
+++ b/src/algorithms/signal_source/libs/fpga_spidev.cc
@@ -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 // for memset()
+#include // for open(), O_RDWR
+#include // for std::cerr
+#include // spidev driver
+#include // for ioctl()
+#include // 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);
+}
diff --git a/src/algorithms/signal_source/libs/fpga_spidev.h b/src/algorithms/signal_source/libs/fpga_spidev.h
new file mode 100644
index 000000000..5fbe2f41c
--- /dev/null
+++ b/src/algorithms/signal_source/libs/fpga_spidev.h
@@ -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
+
+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
diff --git a/src/algorithms/signal_source/libs/fpga_switch.cc b/src/algorithms/signal_source/libs/fpga_switch.cc
index f2d51c2fb..2730bdf36 100644
--- a/src/algorithms/signal_source/libs/fpga_switch.cc
+++ b/src/algorithms/signal_source/libs/fpga_switch.cc
@@ -21,6 +21,7 @@
*/
#include "fpga_switch.h"
+#include "uio_fpga.h"
#include // for open, O_RDWR, O_SYNC
#include // for cout
#include // for mmap
@@ -32,11 +33,19 @@
#include
#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(mmap(nullptr, FPGA_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));
diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h
index b4a73cb4f..8a46c214d 100644
--- a/src/algorithms/signal_source/libs/fpga_switch.h
+++ b/src/algorithms/signal_source/libs/fpga_switch.h
@@ -42,8 +42,7 @@ public:
/*!
* \brief Constructor
*/
- explicit Fpga_Switch(const std::string& device_name);
-
+ Fpga_Switch(void);
/*!
* \brief Destructor
*/
@@ -55,6 +54,7 @@ public:
void set_switch_position(int32_t switch_position);
private:
+ const std::string SWITCH_DEVICE_NAME = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name
static const size_t FPGA_PAGE_SIZE = 0x1000;
static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA;
static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50;
diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h
index 722440f32..8de75e087 100644
--- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h
+++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h
@@ -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
{
- return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga";
+ return "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA";
}
/*!
diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h
index 510df45ea..1b3c8f52b 100644
--- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h
+++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h
@@ -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
{
- return "Galileo_E5a_DLL_PLL_Tracking_Fpga";
+ return "Galileo_E5a_DLL_PLL_Tracking_FPGA";
}
/*!
diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h
index dedefd7c5..ed3b23f4a 100644
--- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h
+++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h
@@ -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
{
- return "GPS_L1_CA_DLL_PLL_Tracking_Fpga";
+ return "GPS_L1_CA_DLL_PLL_Tracking_FPGA";
}
/*!
diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h
index 506e8fec6..a89dd5d55 100644
--- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h
+++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h
@@ -57,10 +57,10 @@ public:
return role_;
}
- //! Returns "GPS_L2_M_DLL_PLL_Tracking_Fpga"
+ //! Returns "GPS_L2_M_DLL_PLL_Tracking_FPGA"
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
diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h
index 24fc37a14..ed85735b2 100644
--- a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h
+++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h
@@ -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
{
- return "GPS_L5_DLL_PLL_Tracking_Fpga";
+ return "GPS_L5_DLL_PLL_Tracking_FPGA";
}
/*!
diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt
index 0dfc09a84..cacef7f6f 100644
--- a/src/core/receiver/CMakeLists.txt
+++ b/src/core/receiver/CMakeLists.txt
@@ -98,6 +98,14 @@ if(ENABLE_AD9361)
target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1)
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(GROSMOSDR_FOUND)
target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1)
diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc
index dda8452a8..ce77442ee 100644
--- a/src/core/receiver/gnss_block_factory.cc
+++ b/src/core/receiver/gnss_block_factory.cc
@@ -167,8 +167,17 @@
#include "fmcomms2_signal_source.h"
#endif
-#if AD9361_DRIVER
-#include "ad9361_fpga_signal_source.h"
+#if ENABLE_FPGA and AD9361_DRIVER
+#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
#if LIMESDR_DRIVER
@@ -812,12 +821,34 @@ std::unique_ptr GNSSBlockFactory::GetBlock(
}
#endif
-#if AD9361_DRIVER
- // The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver
- // in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver.
- else if (implementation == "Ad9361_Fpga_Signal_Source")
+#if ENABLE_FPGA and AD9361_DRIVER
+ else if (implementation == "ADRV9361_Z7035_Signal_Source_FPGA")
{
- std::unique_ptr block_ = std::make_unique(configuration, role, in_streams,
+ std::unique_ptr block_ = std::make_unique(configuration, role, in_streams,
+ out_streams, queue);
+ block = std::move(block_);
+ }
+ else if (implementation == "FMCOMMS5_Signal_Source_FPGA")
+ {
+ std::unique_ptr block_ = std::make_unique(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 block_ = std::make_unique(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 block_ = std::make_unique(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
@@ -1054,31 +1085,31 @@ std::unique_ptr GNSSBlockFactory::GetBlock(
}
#endif
#if ENABLE_FPGA
- else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga")
+ else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA")
{
std::unique_ptr block_ = std::make_unique(configuration, role, in_streams,
out_streams);
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 block_ = std::make_unique(configuration, role, in_streams,
out_streams);
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 block_ = std::make_unique(configuration, role, in_streams,
out_streams);
block = std::move(block_);
}
- else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga")
+ else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA")
{
std::unique_ptr block_ = std::make_unique(configuration, role, in_streams,
out_streams);
block = std::move(block_);
}
- else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga")
+ else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA")
{
std::unique_ptr block_ = std::make_unique(configuration, role, in_streams,
out_streams);
@@ -1204,31 +1235,31 @@ std::unique_ptr GNSSBlockFactory::GetBlock(
}
#endif
#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 block_ = std::make_unique(configuration, role, in_streams,
out_streams);
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 block_ = std::make_unique(configuration, role, in_streams,
out_streams);
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