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 - * - * ----------------------------------------------------------------------------- - * - * 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 block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); @@ -1492,31 +1523,31 @@ std::unique_ptr GNSSBlockFactory::GetAcqBlock( } #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); @@ -1660,31 +1691,31 @@ std::unique_ptr GNSSBlockFactory::GetTrkBlock( } #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 block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index d27da6070..c7cbb9f07 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -554,7 +554,7 @@ int GNSSFlowgraph::connect_fpga_flowgraph() if (src == nullptr) { help_hint_ += " * Check implementation name for SignalSource block.\n"; - help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source\n"; + help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Signal_Source_Fpga or Fpga_DMA_2Signal_Source\n"; return 1; } if (src->item_size() == 0) diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc index 816dbfe1a..4d68363f8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc @@ -67,7 +67,7 @@ class GalileoE1PcpsAmbiguousAcquisitionTestFpga : public ::testing::Test { public: bool acquire_signal(); - std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; std::vector gnss_synchro_vec; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; @@ -321,7 +321,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal @@ -397,7 +397,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init() { config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"); + config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"); config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc index ee06f57ce..47ddc54aa 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc @@ -66,7 +66,7 @@ class GpsL1CaPcpsAcquisitionTestFpga : public ::testing::Test { public: bool acquire_signal(); - std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; std::vector gnss_synchro_vec; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; @@ -320,7 +320,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal @@ -396,7 +396,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() void GpsL1CaPcpsAcquisitionTestFpga::init() { config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_Fpga"); + config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_FPGA"); config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc index 9824e1d17..c466a277b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc @@ -638,11 +638,11 @@ bool HybridObservablesTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "1C"; @@ -654,7 +654,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "1B"; @@ -666,7 +666,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "5X"; @@ -678,7 +678,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 1; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "L5"; @@ -732,19 +732,19 @@ bool HybridObservablesTestFpga::acquire_signal() // number of samples that the DMA has to transfer unsigned int nsamples_to_transfer; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); } - else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); } @@ -762,7 +762,7 @@ bool HybridObservablesTestFpga::acquire_signal() acquisition->init(); acquisition->set_local_code(); - if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) { // Skip the first TEST_OBS_SKIP_SAMPLES samples args.skip_used_samples = 0; @@ -910,7 +910,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); std::string System_and_Signal; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { gnss_synchro_master.System = 'G'; std::string signal = "1C"; @@ -923,7 +923,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { gnss_synchro_master.System = 'E'; std::string signal = "1B"; @@ -939,7 +939,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) { gnss_synchro_master.System = 'E'; std::string signal = "5X"; @@ -953,7 +953,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { gnss_synchro_master.System = 'G'; std::string signal = "L5"; @@ -2031,22 +2031,22 @@ TEST_F(HybridObservablesTestFpga, ValidationOfResults) args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR; // reset the HW to clear the sample counters: the acquisition constructor generates a reset - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc index 4bd43fc30..d5f2348af 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc @@ -355,7 +355,7 @@ void GpsL1CADllPllTrackingTestFpga::configure_receiver() std::to_string(baseband_sampling_freq)); // Set Tracking config->set_property("Tracking_1C.implementation", - "GPS_L1_CA_DLL_PLL_Tracking_Fpga"); + "GPS_L1_CA_DLL_PLL_Tracking_FPGA"); config->set_property("Tracking_1C.item_type", "cshort"); config->set_property("Tracking_1C.dump", "true"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc index 39f87bdfa..a2f27204e 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc @@ -536,7 +536,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); std::string System_and_Signal; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { gnss_synchro.System = 'G'; std::string signal = "1C"; @@ -545,7 +545,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { gnss_synchro.System = 'E'; std::string signal = "1B"; @@ -557,7 +557,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); config->set_property("Tracking.track_pilot", "true"); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") { gnss_synchro.System = 'E'; std::string signal = "5X"; @@ -565,13 +565,13 @@ void TrackingPullInTestFpga::configure_receiver( signal.copy(gnss_synchro.Signal, 2, 0); if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b") { - config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_Fpga")); + config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_FPGA")); } config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.track_pilot", "true"); config->set_property("Tracking.order", "2"); } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { gnss_synchro.System = 'G'; std::string signal = "L5"; @@ -634,11 +634,11 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "1C"; @@ -650,7 +650,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "1B"; @@ -662,7 +662,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "5X"; @@ -674,7 +674,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 1; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "L5"; @@ -732,19 +732,19 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) // number of samples that the DMA has to transfer unsigned int nsamples_to_transfer; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); } - else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); } @@ -762,7 +762,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) acquisition->init(); acquisition->set_local_code(); - if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) { // Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal // states of the downsampling filter in the FPGA @@ -1079,22 +1079,22 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) std::shared_ptr acquisition; // reset the HW to clear the sample counters: the acquisition constructor generates a reset - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1;