mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-30 23:03:05 +00:00 
			
		
		
		
	Merge branch 'mmajoral-fpga_signal_sources' into next
This commit is contained in:
		
							
								
								
									
										107
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								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_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF) | ||||||
|  |  | ||||||
|  | option(ENABLE_MAX2771 "Enable the use of MAX2771 direct to FPGA hardware, requires the spidev driver" OFF) | ||||||
|  |  | ||||||
|  | option(ENABLE_DMA_PROXY "Enable the use of the DMA direct to FPGA hardware, requires the DMA Proxy driver" OFF) | ||||||
|  |  | ||||||
| option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) | option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) | ||||||
|  |  | ||||||
| option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF) | option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF) | ||||||
| @@ -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 | # 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_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") | ||||||
| add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") | add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") | ||||||
| add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") | add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") | ||||||
|  | add_feature_info(ENABLE_MAX2771 ENABLE_MAX2771 "Enables FPGA_MAX2771_EVKIT_Signal_Source for devices with the MAX2771 chipset. Requires the spidev driver") | ||||||
|  | add_feature_info(ENABLE_DMA_PROXY ENABLE_DMA_PROXY "Enables DMA Signal_Source. Requires the DMA Proxy driver") | ||||||
| add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") | add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") | ||||||
| add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") | add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") | ||||||
| add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") | add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") | ||||||
|   | |||||||
| @@ -21,6 +21,25 @@ All notable changes to GNSS-SDR will be documented in this file. | |||||||
|   wideband device (HackRF/LimeSDR/USRP). Demonstration: |   wideband device (HackRF/LimeSDR/USRP). Demonstration: | ||||||
|   https://www.youtube.com/watch?v=ZQs2sFchJ6w |   https://www.youtube.com/watch?v=ZQs2sFchJ6w | ||||||
|   https://www.youtube.com/watch?v=HnZkKj9a-QM |   https://www.youtube.com/watch?v=HnZkKj9a-QM | ||||||
|  | - Add the following signal sources for use when GNSS-SDR is operating on SoC | ||||||
|  |   FPGA boards (`-DENABLE_FPGA=ON`): | ||||||
|  |  | ||||||
|  |   - `ADRV9361_Z7035_Signal_Source_FPGA`: Analog Devices ADRV9361-Z7035 board. | ||||||
|  |   - `FMCOMMS5_Signal_Source_FPGA`: FMCOMMS5 analog front-end. | ||||||
|  |   - `MAX2771_EVKIT_Signal_Source_FPGA`: MAX2771 evaluation kit analog front-end. | ||||||
|  |   - `DMA_Signal_Source_FPGA`: FPGA DMA working in post-processing mode. | ||||||
|  |  | ||||||
|  |   When building GNSS-SDR for the SoC FPGA, the following options can be passed | ||||||
|  |   to CMake with possible values of `ON` or `OFF`, and their default value is | ||||||
|  |   `OFF`: | ||||||
|  |  | ||||||
|  |   - `-DENABLE_AD9361`: Checks if the IIO driver is installed and builds the | ||||||
|  |     `ADRV9361_Z7035_Signal_Source_FPGA` and the `FMCOMMS5_Signal_Source_FPGA` | ||||||
|  |     sources. | ||||||
|  |   - `-DENABLE_MAX2771`: Checks if the SPIdev driver is installed and builds the | ||||||
|  |     `MAX2771_EVKIT_Signal_Source_FPGA` source. | ||||||
|  |   - `-DENABLE_DMA_PROXY`: Checks if the DMA proxy driver is installed for | ||||||
|  |     controlling the DMA in the FPGA and enables its usage. | ||||||
|  |  | ||||||
| ### Improvements in Portability: | ### Improvements in Portability: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -66,11 +66,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga" |      * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"; |         return "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -66,11 +66,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "Galileo_E5a_Pcps_Acquisition_Fpga" |      * \brief Returns "Galileo_E5a_Pcps_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "Galileo_E5a_Pcps_Acquisition_Fpga"; |         return "Galileo_E5a_Pcps_Acquisition_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "Galileo_E5b_Pcps_Acquisition_Fpga" |      * \brief Returns "Galileo_E5b_Pcps_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -67,11 +67,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "GPS_L1_CA_PCPS_Acquisition_Fpga" |      * \brief Returns "GPS_L1_CA_PCPS_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L1_CA_PCPS_Acquisition_Fpga"; |         return "GPS_L1_CA_PCPS_Acquisition_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -60,11 +60,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "GPS_L2_M_PCPS_Acquisition_Fpga" |      * \brief Returns "GPS_L2_M_PCPS_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L2_M_PCPS_Acquisition_Fpga"; |         return "GPS_L2_M_PCPS_Acquisition_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline size_t item_size() override |     inline size_t item_size() override | ||||||
|   | |||||||
| @@ -69,11 +69,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "GPS_L5i_PCPS_Acquisition_Fpga" |      * \brief Returns "GPS_L5i_PCPS_Acquisition_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L5i_PCPS_Acquisition_Fpga"; |         return "GPS_L5i_PCPS_Acquisition_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -37,8 +37,26 @@ if(ENABLE_AD9361) | |||||||
|     ############################################### |     ############################################### | ||||||
|     # AD9361 DIRECT TO FPGA Hardware |     # AD9361 DIRECT TO FPGA Hardware | ||||||
|     ############################################### |     ############################################### | ||||||
|     list(APPEND OPT_DRIVER_SOURCES ad9361_fpga_signal_source.cc) |     list(APPEND OPT_DRIVER_SOURCES adrv9361_z7035_signal_source_fpga.cc) | ||||||
|     list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h) |     list(APPEND OPT_DRIVER_HEADERS adrv9361_z7035_signal_source_fpga.h) | ||||||
|  |     list(APPEND OPT_DRIVER_SOURCES fmcomms5_signal_source_fpga.cc) | ||||||
|  |     list(APPEND OPT_DRIVER_HEADERS fmcomms5_signal_source_fpga.h) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_MAX2771) | ||||||
|  |     ############################################### | ||||||
|  |     # MAX2771 EVKIT DIRECT TO FPGA Hardware | ||||||
|  |     ############################################### | ||||||
|  |     list(APPEND OPT_DRIVER_SOURCES max2771_evkit_signal_source_fpga.cc) | ||||||
|  |     list(APPEND OPT_DRIVER_HEADERS max2771_evkit_signal_source_fpga.h) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_DMA_PROXY) | ||||||
|  |     ############################################### | ||||||
|  |     # FPGA DMA source | ||||||
|  |     ############################################### | ||||||
|  |     list(APPEND OPT_DRIVER_SOURCES dma_signal_source_fpga.cc) | ||||||
|  |     list(APPEND OPT_DRIVER_HEADERS dma_signal_source_fpga.h) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) | if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) | ||||||
|   | |||||||
| @@ -1,885 +0,0 @@ | |||||||
| /*! |  | ||||||
|  * \file ad9361_fpga_signal_source.cc |  | ||||||
|  * \brief signal source for Analog Devices front-end AD9361 connected directly |  | ||||||
|  * to FPGA accelerators. |  | ||||||
|  * This source implements only the AD9361 control. It is NOT compatible with |  | ||||||
|  * conventional SDR acquisition and tracking blocks. |  | ||||||
|  * Please use the fmcomms2 source if conventional SDR acquisition and tracking |  | ||||||
|  * is selected in the configuration file. |  | ||||||
|  * \authors <ul> |  | ||||||
|  *          <li> Javier Arribas, jarribas(at)cttc.es |  | ||||||
|  *          <li> Marc Majoral, mmajoral(at)cttc.es |  | ||||||
|  *          </ul> |  | ||||||
|  * |  | ||||||
|  * ----------------------------------------------------------------------------- |  | ||||||
|  * |  | ||||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. |  | ||||||
|  * This file is part of GNSS-SDR. |  | ||||||
|  * |  | ||||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) |  | ||||||
|  * SPDX-License-Identifier: GPL-3.0-or-later |  | ||||||
|  * |  | ||||||
|  * ----------------------------------------------------------------------------- |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "ad9361_fpga_signal_source.h" |  | ||||||
| #include "GPS_L1_CA.h" |  | ||||||
| #include "GPS_L5.h" |  | ||||||
| #include "ad9361_manager.h" |  | ||||||
| #include "command_event.h" |  | ||||||
| #include "configuration_interface.h" |  | ||||||
| #include "gnss_sdr_flags.h" |  | ||||||
| #include "gnss_sdr_string_literals.h" |  | ||||||
| #include "uio_fpga.h" |  | ||||||
| #include <iio.h> |  | ||||||
| #include <algorithm>  // for std::max |  | ||||||
| #include <chrono>     // for std::chrono |  | ||||||
| #include <cmath>      // for std::floor |  | ||||||
| #include <exception>  // for std::exception |  | ||||||
| #include <fcntl.h>    // for open, O_WRONLY |  | ||||||
| #include <fstream>    // for std::ifstream |  | ||||||
| #include <iomanip>    // for std::setprecision |  | ||||||
| #include <iostream>   // for std::cout |  | ||||||
| #include <unistd.h>   // for write |  | ||||||
| #include <vector>     // fr std::vector |  | ||||||
|  |  | ||||||
| #if USE_GLOG_AND_GFLAGS |  | ||||||
| #include <glog/logging.h> |  | ||||||
| #else |  | ||||||
| #include <absl/log/check.h> |  | ||||||
| #include <absl/log/log.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| using namespace std::string_literals; |  | ||||||
|  |  | ||||||
| Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, |  | ||||||
|     const std::string &role, unsigned int in_stream, unsigned int out_stream, |  | ||||||
|     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) |  | ||||||
|     : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), |  | ||||||
|       queue_(queue), |  | ||||||
|       gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), |  | ||||||
|       gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), |  | ||||||
|       rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), |  | ||||||
|       filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), |  | ||||||
|       filename0_(configuration->property(role + ".filename", empty_string)), |  | ||||||
|       rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), |  | ||||||
|       rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), |  | ||||||
|       scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), |  | ||||||
|       phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), |  | ||||||
|       tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), |  | ||||||
|       freq0_(configuration->property(role + ".freq", 0)), |  | ||||||
|       freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))), |  | ||||||
|       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), |  | ||||||
|       bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), |  | ||||||
|       samples_to_skip_(0), |  | ||||||
|       samples_(configuration->property(role + ".samples", static_cast<int64_t>(0))), |  | ||||||
|       freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), |  | ||||||
|       freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast<uint64_t>(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))), |  | ||||||
|       tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(500000))), |  | ||||||
|       Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))), |  | ||||||
|       Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))), |  | ||||||
|       num_input_files_(1), |  | ||||||
|       dma_buff_offset_pos_(0), |  | ||||||
|       in_stream_(in_stream), |  | ||||||
|       out_stream_(out_stream), |  | ||||||
|       switch_position_(configuration->property(role + ".switch_position", 0)), |  | ||||||
|       item_size_(sizeof(int8_t)), |  | ||||||
|       enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), |  | ||||||
|       filter_auto_(configuration->property(role + ".filter_auto", false)), |  | ||||||
|       quadrature_(configuration->property(role + ".quadrature", true)), |  | ||||||
|       rf_dc_(configuration->property(role + ".rf_dc", true)), |  | ||||||
|       bb_dc_(configuration->property(role + ".bb_dc", true)), |  | ||||||
|       rx1_enable_(configuration->property(role + ".rx1_enable", true)), |  | ||||||
|       rx2_enable_(configuration->property(role + ".rx2_enable", true)), |  | ||||||
|       enable_DMA_(false), |  | ||||||
|       enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), |  | ||||||
|       enable_ovf_check_buffer_monitor_active_(false), |  | ||||||
|       dump_(configuration->property(role + ".dump", false)), |  | ||||||
| #if USE_GLOG_AND_GFLAGS |  | ||||||
|       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)), |  | ||||||
| #else |  | ||||||
|       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))), |  | ||||||
| #endif |  | ||||||
|       repeat_(configuration->property(role + ".repeat", false)) |  | ||||||
| { |  | ||||||
|     const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", 0.0); |  | ||||||
|     const size_t header_size = configuration->property(role + ".header_size", 0); |  | ||||||
|  |  | ||||||
|     const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || |  | ||||||
|                                (configuration->property("Channels_1B.count", 0) > 0)); |  | ||||||
|     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || |  | ||||||
|                                (configuration->property("Channels_L5.count", 0) > 0) || |  | ||||||
|                                (configuration->property("Channels_5X.count", 0) > 0)); |  | ||||||
|  |  | ||||||
|     const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; |  | ||||||
|     if (freq0_ == 0) |  | ||||||
|         { |  | ||||||
|             // use ".freq0" |  | ||||||
|             freq0_ = configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (filter_auto_) |  | ||||||
|         { |  | ||||||
|             filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); |  | ||||||
|         } |  | ||||||
|     else |  | ||||||
|         { |  | ||||||
|             filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); |  | ||||||
|         } |  | ||||||
| #if USE_GLOG_AND_GFLAGS |  | ||||||
|     // override value with commandline flag, if present |  | ||||||
|     if (FLAGS_signal_source != "-") |  | ||||||
|         { |  | ||||||
|             filename0_ = FLAGS_signal_source; |  | ||||||
|         } |  | ||||||
|     if (FLAGS_s != "-") |  | ||||||
|         { |  | ||||||
|             filename0_ = FLAGS_s; |  | ||||||
|         } |  | ||||||
| #else |  | ||||||
|     if (absl::GetFlag(FLAGS_signal_source) != "-") |  | ||||||
|         { |  | ||||||
|             filename0_ = absl::GetFlag(FLAGS_signal_source); |  | ||||||
|         } |  | ||||||
|     if (absl::GetFlag(FLAGS_s) != "-") |  | ||||||
|         { |  | ||||||
|             filename0_ = absl::GetFlag(FLAGS_s); |  | ||||||
|         } |  | ||||||
| #endif |  | ||||||
|     if (filename0_.empty()) |  | ||||||
|         { |  | ||||||
|             num_input_files_ = 2; |  | ||||||
|             filename0_ = configuration->property(role + ".filename0", empty_string); |  | ||||||
|             filename1_ = configuration->property(role + ".filename1", empty_string); |  | ||||||
|         } |  | ||||||
|     // if only one input file is specified in the configuration file then: |  | ||||||
|     // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels |  | ||||||
|     // otherwise the DMA transfers the samples to the L2/L5 frequency band channels |  | ||||||
|     // if more than one input file are specified then the DMA transfer the samples to both the L1 and the L2/L5 frequency channels. |  | ||||||
|     if (filename1_.empty()) |  | ||||||
|         { |  | ||||||
|             if (enable_rx1_band) |  | ||||||
|                 { |  | ||||||
|                     dma_buff_offset_pos_ = 2; |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|     else |  | ||||||
|         { |  | ||||||
|             dma_buff_offset_pos_ = 2; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (seconds_to_skip > 0) |  | ||||||
|         { |  | ||||||
|             samples_to_skip_ = static_cast<uint64_t>(seconds_to_skip * sample_rate_) * 2; |  | ||||||
|         } |  | ||||||
|     if (header_size > 0) |  | ||||||
|         { |  | ||||||
|             samples_to_skip_ += header_size; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     std::string device_io_name;  // Switch UIO device file |  | ||||||
|     // find the uio device file corresponding to the switch. |  | ||||||
|     if (find_uio_dev_file_name(device_io_name, switch_device_name, 0) < 0) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << '\n'; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (switch_position_ != 0 && switch_position_ != 2) |  | ||||||
|         { |  | ||||||
|             std::cout << "SignalSource.switch_position configuration parameter must be either 0: read from file(s) via DMA, or 2: read from AD9361\n"; |  | ||||||
|             std::cout << "SignalSource.switch_position configuration parameter set to its default value switch_position=0 - read from file(s)\n"; |  | ||||||
|             switch_position_ = 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     switch_fpga = std::make_shared<Fpga_Switch>(device_io_name); |  | ||||||
|     switch_fpga->set_switch_position(switch_position_); |  | ||||||
|  |  | ||||||
|     if (switch_position_ == 0)  // Inject file(s) via DMA |  | ||||||
|         { |  | ||||||
|             enable_DMA_ = true; |  | ||||||
|  |  | ||||||
|             if (samples_ == 0)  // read all file |  | ||||||
|                 { |  | ||||||
|                     /*! |  | ||||||
|                      * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. |  | ||||||
|                      * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the |  | ||||||
|                      * valve block |  | ||||||
|                      */ |  | ||||||
|                     std::ifstream file(filename0_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); |  | ||||||
|                     std::ifstream::pos_type size; |  | ||||||
|  |  | ||||||
|                     if (file.is_open()) |  | ||||||
|                         { |  | ||||||
|                             size = file.tellg(); |  | ||||||
|                             DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); |  | ||||||
|                         } |  | ||||||
|                     else |  | ||||||
|                         { |  | ||||||
|                             std::cerr << "SignalSource: Unable to open the samples file " << filename0_.c_str() << '\n'; |  | ||||||
|                             return; |  | ||||||
|                         } |  | ||||||
|                     std::streamsize ss = std::cout.precision(); |  | ||||||
|                     std::cout << std::setprecision(16); |  | ||||||
|                     std::cout << "Processing file " << filename0_ << ", which contains " << static_cast<double>(size) << " [bytes]\n"; |  | ||||||
|                     std::cout.precision(ss); |  | ||||||
|  |  | ||||||
|                     if (size > 0) |  | ||||||
|                         { |  | ||||||
|                             const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; |  | ||||||
|                             const uint64_t bytes_to_process = static_cast<uint64_t>(size) - bytes_to_skip; |  | ||||||
|                             samples_ = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_)));  // process all the samples available in the file excluding at least the last 1 ms |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     if (!filename1_.empty()) |  | ||||||
|                         { |  | ||||||
|                             std::ifstream file(filename1_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); |  | ||||||
|                             std::ifstream::pos_type size; |  | ||||||
|  |  | ||||||
|                             if (file.is_open()) |  | ||||||
|                                 { |  | ||||||
|                                     size = file.tellg(); |  | ||||||
|                                     DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); |  | ||||||
|                                 } |  | ||||||
|                             else |  | ||||||
|                                 { |  | ||||||
|                                     std::cerr << "SignalSource: Unable to open the samples file " << filename1_.c_str() << '\n'; |  | ||||||
|                                     return; |  | ||||||
|                                 } |  | ||||||
|                             std::streamsize ss = std::cout.precision(); |  | ||||||
|                             std::cout << std::setprecision(16); |  | ||||||
|                             std::cout << "Processing file " << filename1_ << ", which contains " << static_cast<double>(size) << " [bytes]\n"; |  | ||||||
|                             std::cout.precision(ss); |  | ||||||
|  |  | ||||||
|                             int64_t samples_rx2 = 0; |  | ||||||
|                             if (size > 0) |  | ||||||
|                                 { |  | ||||||
|                                     const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; |  | ||||||
|                                     const uint64_t bytes_to_process = static_cast<uint64_t>(size) - bytes_to_skip; |  | ||||||
|                                     samples_rx2 = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_)));  // process all the samples available in the file excluding at least the last 1 ms |  | ||||||
|                                 } |  | ||||||
|                             samples_ = std::min(samples_, samples_rx2); |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             CHECK(samples_ > 0) << "File does not contain enough samples to process."; |  | ||||||
|             double signal_duration_s = (static_cast<double>(samples_) * (1 / static_cast<double>(sample_rate_))) / 2.0; |  | ||||||
|  |  | ||||||
|             DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; |  | ||||||
|             std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; |  | ||||||
|  |  | ||||||
|             if (filename1_.empty()) |  | ||||||
|                 { |  | ||||||
|                     DLOG(INFO) << "File source filename " << filename0_; |  | ||||||
|                 } |  | ||||||
|             else |  | ||||||
|                 { |  | ||||||
|                     DLOG(INFO) << "File source filename rx1 " << filename0_; |  | ||||||
|                     DLOG(INFO) << "File source filename rx2 " << filename1_; |  | ||||||
|                 } |  | ||||||
|             DLOG(INFO) << "Samples " << samples_; |  | ||||||
|             DLOG(INFO) << "Sampling frequency " << sample_rate_; |  | ||||||
|             DLOG(INFO) << "Item type " << std::string("ibyte"); |  | ||||||
|             DLOG(INFO) << "Item size " << item_size_; |  | ||||||
|             DLOG(INFO) << "Repeat " << repeat_; |  | ||||||
|         } |  | ||||||
|     if (switch_position_ == 2)  // Real-time via AD9361 |  | ||||||
|         { |  | ||||||
|             std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; |  | ||||||
|  |  | ||||||
|             enable_ovf_check_buffer_monitor_active_ = false;  // check buffer overflow and buffer monitor disabled by default |  | ||||||
|  |  | ||||||
|             // some basic checks |  | ||||||
|             if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; |  | ||||||
|                     std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; |  | ||||||
|                     std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; |  | ||||||
|                     std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; |  | ||||||
|                     rf_port_select_ = default_rf_port_select; |  | ||||||
|                     LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; |  | ||||||
|                     std::cout << " manual, slow_attack, fast_attack, hybrid\n"; |  | ||||||
|                     std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; |  | ||||||
|                     std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; |  | ||||||
|                     gain_mode_rx1_ = default_gain_mode; |  | ||||||
|                     LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; |  | ||||||
|                     std::cout << " manual, slow_attack, fast_attack, hybrid\n"; |  | ||||||
|                     std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; |  | ||||||
|                     std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; |  | ||||||
|                     gain_mode_rx2_ = default_gain_mode; |  | ||||||
|                     LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if (gain_mode_rx1_ == "manual") |  | ||||||
|                 { |  | ||||||
|                     if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; |  | ||||||
|                             std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; |  | ||||||
|                             std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; |  | ||||||
|                             rf_gain_rx1_ = default_manual_gain_rx1; |  | ||||||
|                             LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if (gain_mode_rx2_ == "manual") |  | ||||||
|                 { |  | ||||||
|                     if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; |  | ||||||
|                             std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; |  | ||||||
|                             std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; |  | ||||||
|                             rf_gain_rx2_ = default_manual_gain_rx2; |  | ||||||
|                             LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "Configuration parameter filter_source should take one of these values:\n"; |  | ||||||
|                     std::cout << "  Off: Disable filter\n"; |  | ||||||
|                     std::cout << "  Auto: Use auto-generated filters\n"; |  | ||||||
|                     std::cout << "  File: User-provided filter in filter_filename parameter\n"; |  | ||||||
|                     std::cout << "  Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; |  | ||||||
|                     std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; |  | ||||||
|                     std::cout << " This parameter has been set to its default value filter_source=Off\n"; |  | ||||||
|                     filter_source_ = std::string("Off"); |  | ||||||
|                     LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if (bandwidth_ < 200000 || bandwidth_ > 56000000) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; |  | ||||||
|                     std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; |  | ||||||
|                     std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; |  | ||||||
|                     bandwidth_ = default_bandwidth; |  | ||||||
|                     LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             std::cout << "LO frequency : " << freq0_ << " Hz\n"; |  | ||||||
|             try |  | ||||||
|                 { |  | ||||||
|                     config_ad9361_rx_local(bandwidth_, |  | ||||||
|                         sample_rate_, |  | ||||||
|                         freq0_, |  | ||||||
|                         freq1_, |  | ||||||
|                         rf_port_select_, |  | ||||||
|                         rx1_enable_, |  | ||||||
|                         rx2_enable_, |  | ||||||
|                         gain_mode_rx1_, |  | ||||||
|                         gain_mode_rx2_, |  | ||||||
|                         rf_gain_rx1_, |  | ||||||
|                         rf_gain_rx2_, |  | ||||||
|                         quadrature_, |  | ||||||
|                         rf_dc_, |  | ||||||
|                         bb_dc_, |  | ||||||
|                         filter_source_, |  | ||||||
|                         filter_filename_, |  | ||||||
|                         Fpass_, |  | ||||||
|                         Fstop_); |  | ||||||
|                 } |  | ||||||
|             catch (const std::runtime_error &e) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             // LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION |  | ||||||
|             if (enable_dds_lo_ == true) |  | ||||||
|                 { |  | ||||||
|                     if (tx_bandwidth_ < static_cast<uint64_t>(std::floor(static_cast<float>(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000)) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast<float>(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n"; |  | ||||||
|                             std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n"; |  | ||||||
|                             std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n"; |  | ||||||
|                             tx_bandwidth_ = 500000; |  | ||||||
|                             LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000"; |  | ||||||
|                         } |  | ||||||
|                     if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Configuration parameter tx_attenuation_db should take values between 0.0 and -89.95 in 0.25 dB steps\n"; |  | ||||||
|                             std::cout << "Error: provided value tx_attenuation_db=" << tx_attenuation_db_ << " is not among valid values\n"; |  | ||||||
|                             std::cout << " This parameter has been set to its default value tx_attenuation_db=" << default_tx_attenuation_db << '\n'; |  | ||||||
|                             tx_attenuation_db_ = default_tx_attenuation_db; |  | ||||||
|                             LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << default_tx_attenuation_db; |  | ||||||
|                         } |  | ||||||
|                     try |  | ||||||
|                         { |  | ||||||
|                             config_ad9361_lo_local(tx_bandwidth_, |  | ||||||
|                                 sample_rate_, |  | ||||||
|                                 freq_rf_tx_hz_, |  | ||||||
|                                 tx_attenuation_db_, |  | ||||||
|                                 freq_dds_tx_hz_, |  | ||||||
|                                 scale_dds_dbfs_, |  | ||||||
|                                 phase_dds_deg_); |  | ||||||
|                         } |  | ||||||
|                     catch (const std::runtime_error &e) |  | ||||||
|                         { |  | ||||||
|                             std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; |  | ||||||
|                             return; |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             // when the receiver is working in real-time mode via AD9361 perform buffer overflow checking, |  | ||||||
|             // and if dump is enabled perform buffer monitoring |  | ||||||
|             enable_ovf_check_buffer_monitor_active_ = true; |  | ||||||
|  |  | ||||||
|             std::string device_io_name_buffer_monitor; |  | ||||||
|  |  | ||||||
|             std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); |  | ||||||
|  |  | ||||||
|             // find the uio device file corresponding to the buffer monitor |  | ||||||
|             if (find_uio_dev_file_name(device_io_name_buffer_monitor, buffer_monitor_device_name, 0) < 0) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << buffer_monitor_device_name << '\n'; |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(device_io_name_buffer_monitor, num_freq_bands, dump_, dump_filename); |  | ||||||
|             thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     // dynamic bits selection |  | ||||||
|     if (enable_dynamic_bit_selection_) |  | ||||||
|         { |  | ||||||
|             dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band); |  | ||||||
|             thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (in_stream_ > 0) |  | ||||||
|         { |  | ||||||
|             LOG(ERROR) << "A signal source does not have an input stream"; |  | ||||||
|         } |  | ||||||
|     if (out_stream_ > 1) |  | ||||||
|         { |  | ||||||
|             LOG(ERROR) << "This implementation only supports one output stream"; |  | ||||||
|         } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() |  | ||||||
| { |  | ||||||
|     /* cleanup and exit */ |  | ||||||
|     if (switch_position_ == 0)  // read samples from a file via DMA |  | ||||||
|         { |  | ||||||
|             std::unique_lock<std::mutex> lock(dma_mutex); |  | ||||||
|             enable_DMA_ = false;  // disable the DMA |  | ||||||
|             lock.unlock(); |  | ||||||
|             if (thread_file_to_dma.joinable()) |  | ||||||
|                 { |  | ||||||
|                     thread_file_to_dma.join(); |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (switch_position_ == 2)  // Real-time via AD9361 |  | ||||||
|         { |  | ||||||
|             if (rf_shutdown_) |  | ||||||
|                 { |  | ||||||
|                     std::cout << "* AD9361 Disabling RX streaming channels\n"; |  | ||||||
|                     if (!disable_ad9361_rx_local()) |  | ||||||
|                         { |  | ||||||
|                             LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; |  | ||||||
|                         } |  | ||||||
|                     if (enable_dds_lo_) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                                 { |  | ||||||
|                                     ad9361_disable_lo_local(); |  | ||||||
|                                 } |  | ||||||
|                             catch (const std::exception &e) |  | ||||||
|                                 { |  | ||||||
|                                     LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what(); |  | ||||||
|                                 } |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             // disable buffer overflow checking and buffer monitoring |  | ||||||
|             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); |  | ||||||
|             enable_ovf_check_buffer_monitor_active_ = false; |  | ||||||
|             lock.unlock(); |  | ||||||
|  |  | ||||||
|             if (thread_buffer_monitor.joinable()) |  | ||||||
|                 { |  | ||||||
|                     thread_buffer_monitor.join(); |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); |  | ||||||
|     bool bit_selection_enabled = enable_dynamic_bit_selection_; |  | ||||||
|     lock.unlock(); |  | ||||||
|  |  | ||||||
|     if (bit_selection_enabled == true) |  | ||||||
|         { |  | ||||||
|             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); |  | ||||||
|             enable_dynamic_bit_selection_ = false; |  | ||||||
|             lock.unlock(); |  | ||||||
|  |  | ||||||
|             if (thread_dynamic_bit_selection.joinable()) |  | ||||||
|                 { |  | ||||||
|                     thread_dynamic_bit_selection.join(); |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::start() |  | ||||||
| { |  | ||||||
|     thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue<pmt::pmt_t> *queue) |  | ||||||
| { |  | ||||||
|     std::ifstream infile1; |  | ||||||
|     infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     // FPGA DMA control |  | ||||||
|     dma_fpga = std::make_shared<Fpga_DMA>(); |  | ||||||
|  |  | ||||||
|     // open the files |  | ||||||
|     try |  | ||||||
|         { |  | ||||||
|             infile1.open(filename0_, std::ios::binary); |  | ||||||
|         } |  | ||||||
|     catch (const std::ifstream::failure &e) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Exception opening file " << filename0_ << '\n'; |  | ||||||
|             // stop the receiver |  | ||||||
|             queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     std::ifstream infile2; |  | ||||||
|     if (!filename1_.empty()) |  | ||||||
|         { |  | ||||||
|             infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); |  | ||||||
|             try |  | ||||||
|                 { |  | ||||||
|                     infile2.open(filename1_, std::ios::binary); |  | ||||||
|                 } |  | ||||||
|             catch (const std::ifstream::failure &e) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Exception opening file " << filename1_ << '\n'; |  | ||||||
|                     // stop the receiver |  | ||||||
|                     queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     // skip the initial samples if needed |  | ||||||
|     uint64_t bytes_to_skeep = samples_to_skip * item_size; |  | ||||||
|     try |  | ||||||
|         { |  | ||||||
|             infile1.ignore(bytes_to_skeep); |  | ||||||
|         } |  | ||||||
|     catch (const std::ifstream::failure &e) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; |  | ||||||
|             // stop the receiver |  | ||||||
|             queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (!filename1_.empty()) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|                 { |  | ||||||
|                     infile2.ignore(bytes_to_skeep); |  | ||||||
|                 } |  | ||||||
|             catch (const std::ifstream::failure &e) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; |  | ||||||
|                     // stop the receiver |  | ||||||
|                     queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     // rx signal vectors |  | ||||||
|     std::vector<int8_t> input_samples(sample_block_size * 2);  // complex samples |  | ||||||
|     // pointer to DMA buffer |  | ||||||
|     int8_t *dma_buffer; |  | ||||||
|     int nread_elements = 0;  // num bytes read from the file corresponding to frequency band 1 |  | ||||||
|     bool run_DMA = true; |  | ||||||
|  |  | ||||||
|     // Open DMA device |  | ||||||
|     if (dma_fpga->DMA_open()) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Cannot open loop device\n"; |  | ||||||
|             // stop the receiver |  | ||||||
|             queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     dma_buffer = dma_fpga->get_buffer_address(); |  | ||||||
|  |  | ||||||
|     // if only one frequency band is used then clear the samples corresponding to the unused frequency band |  | ||||||
|     uint32_t dma_index = 0; |  | ||||||
|     if (num_input_files_ == 1) |  | ||||||
|         { |  | ||||||
|             // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. |  | ||||||
|             for (int index0 = 0; index0 < (nread_elements); index0 += 2) |  | ||||||
|                 { |  | ||||||
|                     dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; |  | ||||||
|                     dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; |  | ||||||
|                     dma_index += 4; |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     uint64_t nbytes_remaining = samples * item_size; |  | ||||||
|     uint32_t read_buffer_size = sample_block_size * 2;  // complex samples |  | ||||||
|  |  | ||||||
|     // run the DMA |  | ||||||
|     while (run_DMA) |  | ||||||
|         { |  | ||||||
|             dma_index = 0; |  | ||||||
|             if (nbytes_remaining < read_buffer_size) |  | ||||||
|                 { |  | ||||||
|                     read_buffer_size = nbytes_remaining; |  | ||||||
|                 } |  | ||||||
|             nbytes_remaining = nbytes_remaining - read_buffer_size; |  | ||||||
|  |  | ||||||
|             // read filename 0 |  | ||||||
|             try |  | ||||||
|                 { |  | ||||||
|                     infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); |  | ||||||
|                 } |  | ||||||
|             catch (const std::ifstream::failure &e) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Exception reading file " << filename0_ << '\n'; |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|             if (infile1) |  | ||||||
|                 { |  | ||||||
|                     nread_elements = read_buffer_size; |  | ||||||
|                 } |  | ||||||
|             else |  | ||||||
|                 { |  | ||||||
|                     // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN |  | ||||||
|                     nread_elements = infile1.gcount(); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             for (int index0 = 0; index0 < (nread_elements); index0 += 2) |  | ||||||
|                 { |  | ||||||
|                     // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands |  | ||||||
|                     dma_buffer[dma_index + dma_buff_offset_pos] = input_samples[index0]; |  | ||||||
|                     dma_buffer[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; |  | ||||||
|                     dma_index += 4; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             // read filename 1 (if enabled) |  | ||||||
|             if (num_input_files_ > 1) |  | ||||||
|                 { |  | ||||||
|                     dma_index = 0; |  | ||||||
|                     try |  | ||||||
|                         { |  | ||||||
|                             infile2.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); |  | ||||||
|                         } |  | ||||||
|                     catch (const std::ifstream::failure &e) |  | ||||||
|                         { |  | ||||||
|                             std::cerr << "Exception reading file " << filename1_ << '\n'; |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                     if (infile2) |  | ||||||
|                         { |  | ||||||
|                             nread_elements = read_buffer_size; |  | ||||||
|                         } |  | ||||||
|                     else |  | ||||||
|                         { |  | ||||||
|                             // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN |  | ||||||
|                             nread_elements = infile2.gcount(); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     for (int index0 = 0; index0 < (nread_elements); index0 += 2) |  | ||||||
|                         { |  | ||||||
|                             // filename2 is never the L1 band |  | ||||||
|                             dma_buffer[dma_index] = input_samples[index0]; |  | ||||||
|                             dma_buffer[dma_index + 1] = input_samples[index0 + 1]; |  | ||||||
|                             dma_index += 4; |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if (nread_elements > 0) |  | ||||||
|                 { |  | ||||||
|                     if (dma_fpga->DMA_write(nread_elements * 2)) |  | ||||||
|                         { |  | ||||||
|                             std::cerr << "Error: DMA could not send all the required samples\n"; |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                     // Throttle the DMA |  | ||||||
|                     std::this_thread::sleep_for(std::chrono::milliseconds(1)); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             if (nbytes_remaining == 0) |  | ||||||
|                 { |  | ||||||
|                     if (repeat) |  | ||||||
|                         { |  | ||||||
|                             // read the file again |  | ||||||
|                             nbytes_remaining = samples * item_size; |  | ||||||
|                             read_buffer_size = sample_block_size * 2; |  | ||||||
|                             try |  | ||||||
|                                 { |  | ||||||
|                                     infile1.seekg(0); |  | ||||||
|                                 } |  | ||||||
|                             catch (const std::ifstream::failure &e) |  | ||||||
|                                 { |  | ||||||
|                                     std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n'; |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             // skip the initial samples if needed |  | ||||||
|                             uint64_t bytes_to_skeep = samples_to_skip * item_size; |  | ||||||
|                             try |  | ||||||
|                                 { |  | ||||||
|                                     infile1.ignore(bytes_to_skeep); |  | ||||||
|                                 } |  | ||||||
|                             catch (const std::ifstream::failure &e) |  | ||||||
|                                 { |  | ||||||
|                                     std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             if (!filename1_.empty()) |  | ||||||
|                                 { |  | ||||||
|                                     try |  | ||||||
|                                         { |  | ||||||
|                                             infile2.seekg(0); |  | ||||||
|                                         } |  | ||||||
|                                     catch (const std::ifstream::failure &e) |  | ||||||
|                                         { |  | ||||||
|                                             std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n'; |  | ||||||
|                                             break; |  | ||||||
|                                         } |  | ||||||
|  |  | ||||||
|                                     try |  | ||||||
|                                         { |  | ||||||
|                                             infile2.ignore(bytes_to_skeep); |  | ||||||
|                                         } |  | ||||||
|                                     catch (const std::ifstream::failure &e) |  | ||||||
|                                         { |  | ||||||
|                                             std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; |  | ||||||
|                                             break; |  | ||||||
|                                         } |  | ||||||
|                                 } |  | ||||||
|                         } |  | ||||||
|                     else |  | ||||||
|                         { |  | ||||||
|                             // the input file is completely processed. Stop the receiver. |  | ||||||
|                             run_DMA = false; |  | ||||||
|                         } |  | ||||||
|                 } |  | ||||||
|             std::unique_lock<std::mutex> lock(dma_mutex); |  | ||||||
|             if (enable_DMA_ == false) |  | ||||||
|                 { |  | ||||||
|                     run_DMA = false; |  | ||||||
|                 } |  | ||||||
|             lock.unlock(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (dma_fpga->DMA_close()) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Error closing loop device " << '\n'; |  | ||||||
|         } |  | ||||||
|     try |  | ||||||
|         { |  | ||||||
|             infile1.close(); |  | ||||||
|         } |  | ||||||
|     catch (const std::ifstream::failure &e) |  | ||||||
|         { |  | ||||||
|             std::cerr << "Exception closing file " << filename0_ << '\n'; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (num_input_files_ > 1) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|                 { |  | ||||||
|                     infile2.close(); |  | ||||||
|                 } |  | ||||||
|             catch (const std::ifstream::failure &e) |  | ||||||
|                 { |  | ||||||
|                     std::cerr << "Exception closing file " << filename1_ << '\n'; |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     // Stop the receiver |  | ||||||
|     queue->push(pmt::make_any(command_event_make(200, 0))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process() |  | ||||||
| { |  | ||||||
|     bool dynamic_bit_selection_active = true; |  | ||||||
|  |  | ||||||
|     while (dynamic_bit_selection_active) |  | ||||||
|         { |  | ||||||
|             // setting the bit selection to the top bits |  | ||||||
|             dynamic_bit_selection_fpga->bit_selection(); |  | ||||||
|             std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); |  | ||||||
|             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); |  | ||||||
|             if (enable_dynamic_bit_selection_ == false) |  | ||||||
|                 { |  | ||||||
|                     dynamic_bit_selection_active = false; |  | ||||||
|                 } |  | ||||||
|             lock.unlock(); |  | ||||||
|         } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::run_buffer_monitor_process() |  | ||||||
| { |  | ||||||
|     bool enable_ovf_check_buffer_monitor_active = true; |  | ||||||
|  |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); |  | ||||||
|  |  | ||||||
|     while (enable_ovf_check_buffer_monitor_active) |  | ||||||
|         { |  | ||||||
|             buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); |  | ||||||
|             std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); |  | ||||||
|             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); |  | ||||||
|             if (enable_ovf_check_buffer_monitor_active_ == false) |  | ||||||
|                 { |  | ||||||
|                     enable_ovf_check_buffer_monitor_active = false; |  | ||||||
|                 } |  | ||||||
|             lock.unlock(); |  | ||||||
|         } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::connect(gr::top_block_sptr top_block) |  | ||||||
| { |  | ||||||
|     if (top_block) |  | ||||||
|         { /* top_block is not null */ |  | ||||||
|         }; |  | ||||||
|     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void Ad9361FpgaSignalSource::disconnect(gr::top_block_sptr top_block) |  | ||||||
| { |  | ||||||
|     if (top_block) |  | ||||||
|         { /* top_block is not null */ |  | ||||||
|         }; |  | ||||||
|     DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| gr::basic_block_sptr Ad9361FpgaSignalSource::get_left_block() |  | ||||||
| { |  | ||||||
|     LOG(WARNING) << "Trying to get signal source left block."; |  | ||||||
|     return {}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| gr::basic_block_sptr Ad9361FpgaSignalSource::get_right_block() |  | ||||||
| { |  | ||||||
|     return {}; |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,398 @@ | |||||||
|  | /*! | ||||||
|  |  * \file adrv9361_z7035_signal_source_fpga.cc | ||||||
|  |  * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board | ||||||
|  |  * directly connected to the FPGA accelerators. | ||||||
|  |  * This source implements only the AD9361 control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * Please use the fmcomms2 source if conventional SDR acquisition and tracking | ||||||
|  |  * is selected in the configuration file. | ||||||
|  |  * \authors <ul> | ||||||
|  |  *          <li> Javier Arribas, jarribas(at)cttc.es | ||||||
|  |  *          <li> Marc Majoral, mmajoral(at)cttc.es | ||||||
|  |  *          </ul> | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "adrv9361_z7035_signal_source_fpga.h" | ||||||
|  | #include "GPS_L1_CA.h" | ||||||
|  | #include "GPS_L5.h" | ||||||
|  | #include "ad9361_manager.h" | ||||||
|  | #include "configuration_interface.h" | ||||||
|  | #include "gnss_sdr_flags.h" | ||||||
|  | #include "gnss_sdr_string_literals.h" | ||||||
|  | #include <algorithm>  // for std::max | ||||||
|  | #include <chrono>     // for std::chrono | ||||||
|  | #include <cmath>      // for std::floor | ||||||
|  | #include <exception>  // for std::exception | ||||||
|  | #include <iostream>   // for std::cout | ||||||
|  |  | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  | #include <glog/logging.h> | ||||||
|  | #else | ||||||
|  | #include <absl/log/check.h> | ||||||
|  | #include <absl/log/log.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | using namespace std::string_literals; | ||||||
|  |  | ||||||
|  | Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||||
|  |     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) | ||||||
|  |     : SignalSourceBase(configuration, role, "ADRV9361_Z7035_Signal_Source_FPGA"s), | ||||||
|  |       gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), | ||||||
|  |       gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), | ||||||
|  |       rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), | ||||||
|  |       filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), | ||||||
|  |       rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), | ||||||
|  |       rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), | ||||||
|  |       scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), | ||||||
|  |       phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), | ||||||
|  |       tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), | ||||||
|  |       freq0_(configuration->property(role + ".freq", 0)), | ||||||
|  |       freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))), | ||||||
|  |       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), | ||||||
|  |       bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), | ||||||
|  |       freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), | ||||||
|  |       freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast<uint64_t>(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))), | ||||||
|  |       tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(500000))), | ||||||
|  |       Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))), | ||||||
|  |       Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))), | ||||||
|  |       in_stream_(in_stream), | ||||||
|  |       out_stream_(out_stream), | ||||||
|  |       item_size_(sizeof(int8_t)), | ||||||
|  |       enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), | ||||||
|  |       filter_auto_(configuration->property(role + ".filter_auto", false)), | ||||||
|  |       quadrature_(configuration->property(role + ".quadrature", true)), | ||||||
|  |       rf_dc_(configuration->property(role + ".rf_dc", true)), | ||||||
|  |       bb_dc_(configuration->property(role + ".bb_dc", true)), | ||||||
|  |       rx1_enable_(configuration->property(role + ".rx1_enable", true)), | ||||||
|  |       rx2_enable_(configuration->property(role + ".rx2_enable", true)), | ||||||
|  |       enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), | ||||||
|  |       enable_ovf_check_buffer_monitor_active_(true), | ||||||
|  |       dump_(configuration->property(role + ".dump", false)), | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) | ||||||
|  | #else | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) | ||||||
|  | #endif | ||||||
|  | { | ||||||
|  |     const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_1B.count", 0) > 0)); | ||||||
|  |     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_L5.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_5X.count", 0) > 0)); | ||||||
|  |  | ||||||
|  |     const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; | ||||||
|  |     if (freq0_ == 0) | ||||||
|  |         { | ||||||
|  |             // use ".freq0" | ||||||
|  |             freq0_ = configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (filter_auto_) | ||||||
|  |         { | ||||||
|  |             filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|  |     switch_fpga->set_switch_position(switch_to_real_time_mode); | ||||||
|  |  | ||||||
|  |     std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; | ||||||
|  |  | ||||||
|  |     // some basic checks | ||||||
|  |     if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; | ||||||
|  |             std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; | ||||||
|  |             std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; | ||||||
|  |             rf_port_select_ = default_rf_port_select; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; | ||||||
|  |             std::cout << " manual, slow_attack, fast_attack, hybrid\n"; | ||||||
|  |             std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; | ||||||
|  |             gain_mode_rx1_ = default_gain_mode; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; | ||||||
|  |             std::cout << " manual, slow_attack, fast_attack, hybrid\n"; | ||||||
|  |             std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; | ||||||
|  |             gain_mode_rx2_ = default_gain_mode; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (gain_mode_rx1_ == "manual") | ||||||
|  |         { | ||||||
|  |             if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; | ||||||
|  |                     std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; | ||||||
|  |                     rf_gain_rx1_ = default_manual_gain_rx1; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (gain_mode_rx2_ == "manual") | ||||||
|  |         { | ||||||
|  |             if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; | ||||||
|  |                     std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; | ||||||
|  |                     rf_gain_rx2_ = default_manual_gain_rx2; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter filter_source should take one of these values:\n"; | ||||||
|  |             std::cout << "  Off: Disable filter\n"; | ||||||
|  |             std::cout << "  Auto: Use auto-generated filters\n"; | ||||||
|  |             std::cout << "  File: User-provided filter in filter_filename parameter\n"; | ||||||
|  |             std::cout << "  Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; | ||||||
|  |             std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value filter_source=Off\n"; | ||||||
|  |             filter_source_ = std::string("Off"); | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (bandwidth_ < 200000 || bandwidth_ > 56000000) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; | ||||||
|  |             std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; | ||||||
|  |             bandwidth_ = default_bandwidth; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::cout << "LO frequency : " << freq0_ << " Hz\n"; | ||||||
|  |     try | ||||||
|  |         { | ||||||
|  |             config_ad9361_rx_local(bandwidth_, | ||||||
|  |                 sample_rate_, | ||||||
|  |                 freq0_, | ||||||
|  |                 freq1_, | ||||||
|  |                 rf_port_select_, | ||||||
|  |                 rx1_enable_, | ||||||
|  |                 rx2_enable_, | ||||||
|  |                 gain_mode_rx1_, | ||||||
|  |                 gain_mode_rx2_, | ||||||
|  |                 rf_gain_rx1_, | ||||||
|  |                 rf_gain_rx2_, | ||||||
|  |                 quadrature_, | ||||||
|  |                 rf_dc_, | ||||||
|  |                 bb_dc_, | ||||||
|  |                 filter_source_, | ||||||
|  |                 filter_filename_, | ||||||
|  |                 Fpass_, | ||||||
|  |                 Fstop_); | ||||||
|  |         } | ||||||
|  |     catch (const std::runtime_error &e) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     // LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION | ||||||
|  |     if (enable_dds_lo_ == true) | ||||||
|  |         { | ||||||
|  |             if (tx_bandwidth_ < static_cast<uint64_t>(std::floor(static_cast<float>(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000)) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast<float>(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n"; | ||||||
|  |                     std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n"; | ||||||
|  |                     tx_bandwidth_ = 500000; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000"; | ||||||
|  |                 } | ||||||
|  |             if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter tx_attenuation_db should take values between 0.0 and -89.95 in 0.25 dB steps\n"; | ||||||
|  |                     std::cout << "Error: provided value tx_attenuation_db=" << tx_attenuation_db_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value tx_attenuation_db=" << default_tx_attenuation_db << '\n'; | ||||||
|  |                     tx_attenuation_db_ = default_tx_attenuation_db; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << default_tx_attenuation_db; | ||||||
|  |                 } | ||||||
|  |             try | ||||||
|  |                 { | ||||||
|  |                     config_ad9361_lo_local(tx_bandwidth_, | ||||||
|  |                         sample_rate_, | ||||||
|  |                         freq_rf_tx_hz_, | ||||||
|  |                         tx_attenuation_db_, | ||||||
|  |                         freq_dds_tx_hz_, | ||||||
|  |                         scale_dds_dbfs_, | ||||||
|  |                         phase_dds_deg_); | ||||||
|  |                 } | ||||||
|  |             catch (const std::runtime_error &e) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); | ||||||
|  |  | ||||||
|  |     buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(num_freq_bands, dump_, dump_filename); | ||||||
|  |     thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // dynamic bits selection | ||||||
|  |     if (enable_dynamic_bit_selection_) | ||||||
|  |         { | ||||||
|  |             dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band); | ||||||
|  |             thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (in_stream_ > 0) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "A signal source does not have an input stream"; | ||||||
|  |         } | ||||||
|  |     if (out_stream_ > 1) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "This implementation only supports one output stream"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Adrv9361z7035SignalSourceFPGA::~Adrv9361z7035SignalSourceFPGA() | ||||||
|  | { | ||||||
|  |     /* cleanup and exit */ | ||||||
|  |  | ||||||
|  |     if (rf_shutdown_) | ||||||
|  |         { | ||||||
|  |             std::cout << "* AD9361 Disabling RX streaming channels\n"; | ||||||
|  |             if (!disable_ad9361_rx_local()) | ||||||
|  |                 { | ||||||
|  |                     LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; | ||||||
|  |                 } | ||||||
|  |             if (enable_dds_lo_) | ||||||
|  |                 { | ||||||
|  |                     try | ||||||
|  |                         { | ||||||
|  |                             ad9361_disable_lo_local(); | ||||||
|  |                         } | ||||||
|  |                     catch (const std::exception &e) | ||||||
|  |                         { | ||||||
|  |                             LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what(); | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // disable buffer overflow checking and buffer monitoring | ||||||
|  |     std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex); | ||||||
|  |     enable_ovf_check_buffer_monitor_active_ = false; | ||||||
|  |     lock_buffer_monitor.unlock(); | ||||||
|  |  | ||||||
|  |     if (thread_buffer_monitor.joinable()) | ||||||
|  |         { | ||||||
|  |             thread_buffer_monitor.join(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex); | ||||||
|  |     bool bit_selection_enabled = enable_dynamic_bit_selection_; | ||||||
|  |     lock_dyn_bit_sel.unlock(); | ||||||
|  |  | ||||||
|  |     if (bit_selection_enabled == true) | ||||||
|  |         { | ||||||
|  |             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); | ||||||
|  |             enable_dynamic_bit_selection_ = false; | ||||||
|  |             lock.unlock(); | ||||||
|  |  | ||||||
|  |             if (thread_dynamic_bit_selection.joinable()) | ||||||
|  |                 { | ||||||
|  |                     thread_dynamic_bit_selection.join(); | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Adrv9361z7035SignalSourceFPGA::run_dynamic_bit_selection_process() | ||||||
|  | { | ||||||
|  |     bool dynamic_bit_selection_active = true; | ||||||
|  |  | ||||||
|  |     while (dynamic_bit_selection_active) | ||||||
|  |         { | ||||||
|  |             // setting the bit selection to the top bits | ||||||
|  |             dynamic_bit_selection_fpga->bit_selection(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); | ||||||
|  |             if (enable_dynamic_bit_selection_ == false) | ||||||
|  |                 { | ||||||
|  |                     dynamic_bit_selection_active = false; | ||||||
|  |                 } | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process() | ||||||
|  | { | ||||||
|  |     bool enable_ovf_check_buffer_monitor_active = true; | ||||||
|  |  | ||||||
|  |     std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); | ||||||
|  |  | ||||||
|  |     while (enable_ovf_check_buffer_monitor_active) | ||||||
|  |         { | ||||||
|  |             buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); | ||||||
|  |             if (enable_ovf_check_buffer_monitor_active_ == false) | ||||||
|  |                 { | ||||||
|  |                     enable_ovf_check_buffer_monitor_active = false; | ||||||
|  |                 } | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Adrv9361z7035SignalSourceFPGA::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Adrv9361z7035SignalSourceFPGA::disconnect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr Adrv9361z7035SignalSourceFPGA::get_left_block() | ||||||
|  | { | ||||||
|  |     LOG(WARNING) << "Trying to get signal source left block."; | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr Adrv9361z7035SignalSourceFPGA::get_right_block() | ||||||
|  | { | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| /*!
 | /*!
 | ||||||
|  * \file ad9361_fpga_signal_source.h |  * \file adrv9361_z7035_signal_source_fpga.h | ||||||
|  * \brief signal source for Analog Devices front-end AD9361 connected directly |  * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board | ||||||
|  * to FPGA accelerators. |  * directly connected to the FPGA accelerators. | ||||||
|  * This source implements only the AD9361 control. It is NOT compatible with |  * This source implements only the AD9361 control. It is NOT compatible with | ||||||
|  * conventional SDR acquisition and tracking blocks. |  * conventional SDR acquisition and tracking blocks. | ||||||
|  * Please use the fmcomms2 source if conventional SDR acquisition and tracking |  * Please use the fmcomms2 source if conventional SDR acquisition and tracking | ||||||
| @@ -12,14 +12,14 @@ | |||||||
|  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  * This file is part of GNSS-SDR. |  * This file is part of GNSS-SDR. | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2010-2020  (see AUTHORS file for a list of contributors) |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  * SPDX-License-Identifier: GPL-3.0-or-later |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  * |  * | ||||||
|  * ----------------------------------------------------------------------------- |  * ----------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H | #ifndef GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H | ||||||
| #define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H | #define GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H | ||||||
| 
 | 
 | ||||||
| #include "concurrent_queue.h" | #include "concurrent_queue.h" | ||||||
| #include "fpga_buffer_monitor.h" | #include "fpga_buffer_monitor.h" | ||||||
| @@ -44,16 +44,14 @@ | |||||||
| 
 | 
 | ||||||
| class ConfigurationInterface; | class ConfigurationInterface; | ||||||
| 
 | 
 | ||||||
| class Ad9361FpgaSignalSource : public SignalSourceBase | class Adrv9361z7035SignalSourceFPGA : public SignalSourceBase | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, |     Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|         const std::string &role, unsigned int in_stream, |         const std::string &role, unsigned int in_stream, | ||||||
|         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); |         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
| 
 | 
 | ||||||
|     ~Ad9361FpgaSignalSource(); |     ~Adrv9361z7035SignalSourceFPGA(); | ||||||
| 
 |  | ||||||
|     void start() override; |  | ||||||
| 
 | 
 | ||||||
|     inline size_t item_size() override |     inline size_t item_size() override | ||||||
|     { |     { | ||||||
| @@ -66,13 +64,9 @@ public: | |||||||
|     gr::basic_block_sptr get_right_block() override; |     gr::basic_block_sptr get_right_block() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0");          // Switch UIO device name
 |  | ||||||
|     const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector");  // Switch dhnamic bit selector device name
 |  | ||||||
|     const std::string buffer_monitor_device_name = std::string("buffer_monitor");      // buffer monitor device name
 |  | ||||||
|     const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); |     const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); | ||||||
|     const std::string default_rf_port_select = std::string("A_BALANCED"); |     const std::string default_rf_port_select = std::string("A_BALANCED"); | ||||||
|     const std::string default_gain_mode = std::string("slow_attack"); |     const std::string default_gain_mode = std::string("slow_attack"); | ||||||
|     const std::string empty_string; |  | ||||||
|     const double default_tx_attenuation_db = -10.0; |     const double default_tx_attenuation_db = -10.0; | ||||||
|     const double default_manual_gain_rx1 = 64.0; |     const double default_manual_gain_rx1 = 64.0; | ||||||
|     const double default_manual_gain_rx2 = 64.0; |     const double default_manual_gain_rx2 = 64.0; | ||||||
| @@ -86,42 +80,27 @@ private: | |||||||
|     const uint32_t buffer_monitoring_initial_delay_ms = 2000; |     const uint32_t buffer_monitoring_initial_delay_ms = 2000; | ||||||
|     // sample block size when running in post-processing mode
 |     // sample block size when running in post-processing mode
 | ||||||
|     const int sample_block_size = 16384; |     const int sample_block_size = 16384; | ||||||
| 
 |     const int32_t switch_to_real_time_mode = 2; | ||||||
|     void run_DMA_process(const std::string &filename0, |  | ||||||
|         const std::string &filename1, |  | ||||||
|         uint64_t &samples_to_skip, |  | ||||||
|         size_t &item_size, |  | ||||||
|         int64_t &samples, |  | ||||||
|         bool &repeat, |  | ||||||
|         uint32_t &dma_buff_offset_pos, |  | ||||||
|         Concurrent_Queue<pmt::pmt_t> *queue); |  | ||||||
| 
 | 
 | ||||||
|     void run_dynamic_bit_selection_process(); |     void run_dynamic_bit_selection_process(); | ||||||
|     void run_buffer_monitor_process(); |     void run_buffer_monitor_process(); | ||||||
| 
 | 
 | ||||||
|     std::thread thread_file_to_dma; |  | ||||||
|     std::thread thread_dynamic_bit_selection; |     std::thread thread_dynamic_bit_selection; | ||||||
|     std::thread thread_buffer_monitor; |     std::thread thread_buffer_monitor; | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<Fpga_Switch> switch_fpga; |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|     std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; |     std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; | ||||||
|     std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; |     std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; | ||||||
|     std::shared_ptr<Fpga_DMA> dma_fpga; |  | ||||||
| 
 | 
 | ||||||
|     std::mutex dma_mutex; |  | ||||||
|     std::mutex dynamic_bit_selection_mutex; |     std::mutex dynamic_bit_selection_mutex; | ||||||
|     std::mutex buffer_monitor_mutex; |     std::mutex buffer_monitor_mutex; | ||||||
| 
 | 
 | ||||||
|     Concurrent_Queue<pmt::pmt_t> *queue_; |  | ||||||
| 
 |  | ||||||
|     std::string gain_mode_rx1_; |     std::string gain_mode_rx1_; | ||||||
|     std::string gain_mode_rx2_; |     std::string gain_mode_rx2_; | ||||||
|     std::string rf_port_select_; |     std::string rf_port_select_; | ||||||
|     std::string filter_file_; |     std::string filter_file_; | ||||||
|     std::string filter_source_; |     std::string filter_source_; | ||||||
|     std::string filter_filename_; |     std::string filter_filename_; | ||||||
|     std::string filename0_; |  | ||||||
|     std::string filename1_; |  | ||||||
| 
 | 
 | ||||||
|     double rf_gain_rx1_; |     double rf_gain_rx1_; | ||||||
|     double rf_gain_rx2_; |     double rf_gain_rx2_; | ||||||
| @@ -133,19 +112,14 @@ private: | |||||||
|     uint64_t freq1_;  // frequency of local oscillator for ADRV9361-B (if present)
 |     uint64_t freq1_;  // frequency of local oscillator for ADRV9361-B (if present)
 | ||||||
|     uint64_t sample_rate_; |     uint64_t sample_rate_; | ||||||
|     uint64_t bandwidth_; |     uint64_t bandwidth_; | ||||||
|     uint64_t samples_to_skip_; |  | ||||||
|     int64_t samples_; |  | ||||||
|     uint64_t freq_dds_tx_hz_; |     uint64_t freq_dds_tx_hz_; | ||||||
|     uint64_t freq_rf_tx_hz_; |     uint64_t freq_rf_tx_hz_; | ||||||
|     uint64_t tx_bandwidth_; |     uint64_t tx_bandwidth_; | ||||||
| 
 | 
 | ||||||
|     float Fpass_; |     float Fpass_; | ||||||
|     float Fstop_; |     float Fstop_; | ||||||
|     uint32_t num_input_files_; |  | ||||||
|     uint32_t dma_buff_offset_pos_; |  | ||||||
|     uint32_t in_stream_; |     uint32_t in_stream_; | ||||||
|     uint32_t out_stream_; |     uint32_t out_stream_; | ||||||
|     int32_t switch_position_; |  | ||||||
| 
 | 
 | ||||||
|     size_t item_size_; |     size_t item_size_; | ||||||
| 
 | 
 | ||||||
| @@ -156,15 +130,13 @@ private: | |||||||
|     bool bb_dc_; |     bool bb_dc_; | ||||||
|     bool rx1_enable_; |     bool rx1_enable_; | ||||||
|     bool rx2_enable_; |     bool rx2_enable_; | ||||||
|     bool enable_DMA_; |  | ||||||
|     bool enable_dynamic_bit_selection_; |     bool enable_dynamic_bit_selection_; | ||||||
|     bool enable_ovf_check_buffer_monitor_active_; |     bool enable_ovf_check_buffer_monitor_active_; | ||||||
|     bool dump_; |     bool dump_; | ||||||
|     bool rf_shutdown_; |     bool rf_shutdown_; | ||||||
|     bool repeat_; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /** \} */ | /** \} */ | ||||||
| /** \} */ | /** \} */ | ||||||
| #endif  // GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H
 | #endif  // GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H
 | ||||||
							
								
								
									
										581
									
								
								src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										581
									
								
								src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,581 @@ | |||||||
|  | /*! | ||||||
|  |  * \file dma_signal_source_fpga.cc | ||||||
|  |  * \brief signal source for a DMA connected directly to FPGA accelerators. | ||||||
|  |  * This source implements only the DMA control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * \author Marc Majoral, mmajoral(at)cttc.es | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "dma_signal_source_fpga.h" | ||||||
|  | #include "command_event.h" | ||||||
|  | #include "configuration_interface.h" | ||||||
|  | #include "gnss_sdr_flags.h" | ||||||
|  | #include "gnss_sdr_string_literals.h" | ||||||
|  | #include <algorithm>  // for std::min | ||||||
|  | #include <chrono>     // for std::chrono | ||||||
|  | #include <fcntl.h>    // for open, O_WRONLY | ||||||
|  | #include <fstream>    // for std::ifstream | ||||||
|  | #include <iomanip>    // for std::setprecision | ||||||
|  | #include <iostream>   // for std::cout | ||||||
|  | #include <vector>     // fr std::vector | ||||||
|  |  | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  | #include <glog/logging.h> | ||||||
|  | #else | ||||||
|  | #include <absl/log/check.h> | ||||||
|  | #include <absl/log/log.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | using namespace std::string_literals; | ||||||
|  |  | ||||||
|  | DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||||
|  |     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) | ||||||
|  |     : SignalSourceBase(configuration, role, "DMA_Signal_Source_FPGA"s), | ||||||
|  |       queue_(queue), | ||||||
|  |       filename0_(configuration->property(role + ".filename", empty_string)), | ||||||
|  |       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), | ||||||
|  |       samples_to_skip_(0), | ||||||
|  |       samples_(configuration->property(role + ".samples", static_cast<int64_t>(0))), | ||||||
|  |       num_input_files_(1), | ||||||
|  |       dma_buff_offset_pos_(0), | ||||||
|  |       in_stream_(in_stream), | ||||||
|  |       out_stream_(out_stream), | ||||||
|  |       item_size_(sizeof(int8_t)), | ||||||
|  |       enable_DMA_(false), | ||||||
|  |       enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), | ||||||
|  |       repeat_(configuration->property(role + ".repeat", false)) | ||||||
|  | { | ||||||
|  |     const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", 0.0); | ||||||
|  |     const size_t header_size = configuration->property(role + ".header_size", 0); | ||||||
|  |  | ||||||
|  |     const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_1B.count", 0) > 0)); | ||||||
|  |     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_L5.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_5X.count", 0) > 0)); | ||||||
|  |  | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  |     // override value with commandline flag, if present | ||||||
|  |     if (FLAGS_signal_source != "-") | ||||||
|  |         { | ||||||
|  |             filename0_ = FLAGS_signal_source; | ||||||
|  |         } | ||||||
|  |     if (FLAGS_s != "-") | ||||||
|  |         { | ||||||
|  |             filename0_ = FLAGS_s; | ||||||
|  |         } | ||||||
|  | #else | ||||||
|  |     if (absl::GetFlag(FLAGS_signal_source) != "-") | ||||||
|  |         { | ||||||
|  |             filename0_ = absl::GetFlag(FLAGS_signal_source); | ||||||
|  |         } | ||||||
|  |     if (absl::GetFlag(FLAGS_s) != "-") | ||||||
|  |         { | ||||||
|  |             filename0_ = absl::GetFlag(FLAGS_s); | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |     if (filename0_.empty()) | ||||||
|  |         { | ||||||
|  |             num_input_files_ = 2; | ||||||
|  |             filename0_ = configuration->property(role + ".filename0", empty_string); | ||||||
|  |             filename1_ = configuration->property(role + ".filename1", empty_string); | ||||||
|  |         } | ||||||
|  |     // if only one input file is specified in the configuration file then: | ||||||
|  |     // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels | ||||||
|  |     // otherwise the DMA transfers the samples to the L2/L5 frequency band channels | ||||||
|  |     // if more than one input file are specified then the DMA transfer the samples to both the L1 and the L2/L5 frequency channels. | ||||||
|  |     if (filename1_.empty()) | ||||||
|  |         { | ||||||
|  |             if (enable_rx1_band) | ||||||
|  |                 { | ||||||
|  |                     dma_buff_offset_pos_ = 2; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             dma_buff_offset_pos_ = 2; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (seconds_to_skip > 0) | ||||||
|  |         { | ||||||
|  |             samples_to_skip_ = static_cast<uint64_t>(seconds_to_skip * sample_rate_) * 2; | ||||||
|  |         } | ||||||
|  |     if (header_size > 0) | ||||||
|  |         { | ||||||
|  |             samples_to_skip_ += header_size; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|  |     switch_fpga->set_switch_position(switch_to_DMA); | ||||||
|  |  | ||||||
|  |     enable_DMA_ = true; | ||||||
|  |  | ||||||
|  |     if (samples_ == 0)  // read all file | ||||||
|  |         { | ||||||
|  |             std::ifstream file(filename0_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||||
|  |             std::ifstream::pos_type size; | ||||||
|  |  | ||||||
|  |             if (file.is_open()) | ||||||
|  |                 { | ||||||
|  |                     size = file.tellg(); | ||||||
|  |                     DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); | ||||||
|  |                 } | ||||||
|  |             else | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "SignalSource: Unable to open the samples file " << filename0_.c_str() << '\n'; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             std::streamsize ss = std::cout.precision(); | ||||||
|  |             std::cout << std::setprecision(16); | ||||||
|  |             std::cout << "Processing file " << filename0_ << ", which contains " << static_cast<double>(size) << " [bytes]\n"; | ||||||
|  |             std::cout.precision(ss); | ||||||
|  |  | ||||||
|  |             if (size > 0) | ||||||
|  |                 { | ||||||
|  |                     const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; | ||||||
|  |                     const uint64_t bytes_to_process = static_cast<uint64_t>(size) - bytes_to_skip; | ||||||
|  |                     samples_ = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_)));  // process all the samples available in the file excluding at least the last 1 ms | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             if (!filename1_.empty()) | ||||||
|  |                 { | ||||||
|  |                     std::ifstream file(filename1_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); | ||||||
|  |                     std::ifstream::pos_type size; | ||||||
|  |  | ||||||
|  |                     if (file.is_open()) | ||||||
|  |                         { | ||||||
|  |                             size = file.tellg(); | ||||||
|  |                             DLOG(INFO) << "Total samples in the file= " << floor(static_cast<double>(size) / static_cast<double>(item_size_)); | ||||||
|  |                         } | ||||||
|  |                     else | ||||||
|  |                         { | ||||||
|  |                             std::cerr << "SignalSource: Unable to open the samples file " << filename1_.c_str() << '\n'; | ||||||
|  |                             return; | ||||||
|  |                         } | ||||||
|  |                     std::streamsize ss = std::cout.precision(); | ||||||
|  |                     std::cout << std::setprecision(16); | ||||||
|  |                     std::cout << "Processing file " << filename1_ << ", which contains " << static_cast<double>(size) << " [bytes]\n"; | ||||||
|  |                     std::cout.precision(ss); | ||||||
|  |  | ||||||
|  |                     int64_t samples_rx2 = 0; | ||||||
|  |                     if (size > 0) | ||||||
|  |                         { | ||||||
|  |                             const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; | ||||||
|  |                             const uint64_t bytes_to_process = static_cast<uint64_t>(size) - bytes_to_skip; | ||||||
|  |                             samples_rx2 = floor(static_cast<double>(bytes_to_process) / static_cast<double>(item_size_) - ceil(0.002 * static_cast<double>(sample_rate_)));  // process all the samples available in the file excluding at least the last 1 ms | ||||||
|  |                         } | ||||||
|  |                     samples_ = std::min(samples_, samples_rx2); | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     CHECK(samples_ > 0) << "File does not contain enough samples to process."; | ||||||
|  |     double signal_duration_s = (static_cast<double>(samples_) * (1 / static_cast<double>(sample_rate_))) / 2.0; | ||||||
|  |  | ||||||
|  |     DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; | ||||||
|  |     std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; | ||||||
|  |  | ||||||
|  |     if (filename1_.empty()) | ||||||
|  |         { | ||||||
|  |             DLOG(INFO) << "File source filename " << filename0_; | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             DLOG(INFO) << "File source filename rx1 " << filename0_; | ||||||
|  |             DLOG(INFO) << "File source filename rx2 " << filename1_; | ||||||
|  |         } | ||||||
|  |     DLOG(INFO) << "Samples " << samples_; | ||||||
|  |     DLOG(INFO) << "Sampling frequency " << sample_rate_; | ||||||
|  |     DLOG(INFO) << "Item type " << std::string("ibyte"); | ||||||
|  |     DLOG(INFO) << "Item size " << item_size_; | ||||||
|  |     DLOG(INFO) << "Repeat " << repeat_; | ||||||
|  |     //        } | ||||||
|  |  | ||||||
|  |     // dynamic bits selection | ||||||
|  |     if (enable_dynamic_bit_selection_) | ||||||
|  |         { | ||||||
|  |             dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band); | ||||||
|  |             thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (in_stream_ > 0) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "A signal source does not have an input stream"; | ||||||
|  |         } | ||||||
|  |     if (out_stream_ > 1) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "This implementation only supports one output stream"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DMASignalSourceFPGA::~DMASignalSourceFPGA() | ||||||
|  | { | ||||||
|  |     std::unique_lock<std::mutex> lock_DMA(dma_mutex); | ||||||
|  |     enable_DMA_ = false;  // disable the DMA | ||||||
|  |     lock_DMA.unlock(); | ||||||
|  |     if (thread_file_to_dma.joinable()) | ||||||
|  |         { | ||||||
|  |             thread_file_to_dma.join(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex); | ||||||
|  |     bool bit_selection_enabled = enable_dynamic_bit_selection_; | ||||||
|  |     lock_dyn_bit_sel.unlock(); | ||||||
|  |  | ||||||
|  |     if (bit_selection_enabled == true) | ||||||
|  |         { | ||||||
|  |             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); | ||||||
|  |             enable_dynamic_bit_selection_ = false; | ||||||
|  |             lock.unlock(); | ||||||
|  |  | ||||||
|  |             if (thread_dynamic_bit_selection.joinable()) | ||||||
|  |                 { | ||||||
|  |                     thread_dynamic_bit_selection.join(); | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMASignalSourceFPGA::start() | ||||||
|  | { | ||||||
|  |     thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue<pmt::pmt_t> *queue) | ||||||
|  | { | ||||||
|  |     std::ifstream infile1; | ||||||
|  |     infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // FPGA DMA control | ||||||
|  |     dma_fpga = std::make_shared<Fpga_DMA>(); | ||||||
|  |  | ||||||
|  |     // open the files | ||||||
|  |     try | ||||||
|  |         { | ||||||
|  |             infile1.open(filename0_, std::ios::binary); | ||||||
|  |         } | ||||||
|  |     catch (const std::ifstream::failure &e) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Exception opening file " << filename0_ << '\n'; | ||||||
|  |             // stop the receiver | ||||||
|  |             queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::ifstream infile2; | ||||||
|  |     if (!filename1_.empty()) | ||||||
|  |         { | ||||||
|  |             infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); | ||||||
|  |             try | ||||||
|  |                 { | ||||||
|  |                     infile2.open(filename1_, std::ios::binary); | ||||||
|  |                 } | ||||||
|  |             catch (const std::ifstream::failure &e) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Exception opening file " << filename1_ << '\n'; | ||||||
|  |                     // stop the receiver | ||||||
|  |                     queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // skip the initial samples if needed | ||||||
|  |     uint64_t bytes_to_skeep = samples_to_skip * item_size; | ||||||
|  |     try | ||||||
|  |         { | ||||||
|  |             infile1.ignore(bytes_to_skeep); | ||||||
|  |         } | ||||||
|  |     catch (const std::ifstream::failure &e) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; | ||||||
|  |             // stop the receiver | ||||||
|  |             queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (!filename1_.empty()) | ||||||
|  |         { | ||||||
|  |             try | ||||||
|  |                 { | ||||||
|  |                     infile2.ignore(bytes_to_skeep); | ||||||
|  |                 } | ||||||
|  |             catch (const std::ifstream::failure &e) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; | ||||||
|  |                     // stop the receiver | ||||||
|  |                     queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // rx signal vectors | ||||||
|  |     std::vector<int8_t> input_samples(sample_block_size * 2);  // complex samples | ||||||
|  |     // pointer to DMA buffer | ||||||
|  |     int8_t *dma_buffer; | ||||||
|  |     int nread_elements = 0;  // num bytes read from the file corresponding to frequency band 1 | ||||||
|  |     bool run_DMA = true; | ||||||
|  |  | ||||||
|  |     // Open DMA device | ||||||
|  |     if (dma_fpga->DMA_open()) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Cannot open loop device\n"; | ||||||
|  |             // stop the receiver | ||||||
|  |             queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     dma_buffer = dma_fpga->get_buffer_address(); | ||||||
|  |  | ||||||
|  |     // if only one frequency band is used then clear the samples corresponding to the unused frequency band | ||||||
|  |     uint32_t dma_index = 0; | ||||||
|  |     if (num_input_files_ == 1) | ||||||
|  |         { | ||||||
|  |             // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. | ||||||
|  |             for (int index0 = 0; index0 < (nread_elements); index0 += 2) | ||||||
|  |                 { | ||||||
|  |                     dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; | ||||||
|  |                     dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; | ||||||
|  |                     dma_index += 4; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     uint64_t nbytes_remaining = samples * item_size; | ||||||
|  |     uint32_t read_buffer_size = sample_block_size * 2;  // complex samples | ||||||
|  |  | ||||||
|  |     // run the DMA | ||||||
|  |     while (run_DMA) | ||||||
|  |         { | ||||||
|  |             dma_index = 0; | ||||||
|  |             if (nbytes_remaining < read_buffer_size) | ||||||
|  |                 { | ||||||
|  |                     read_buffer_size = nbytes_remaining; | ||||||
|  |                 } | ||||||
|  |             nbytes_remaining = nbytes_remaining - read_buffer_size; | ||||||
|  |  | ||||||
|  |             // read filename 0 | ||||||
|  |             try | ||||||
|  |                 { | ||||||
|  |                     infile1.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); | ||||||
|  |                 } | ||||||
|  |             catch (const std::ifstream::failure &e) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Exception reading file " << filename0_ << '\n'; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             if (infile1) | ||||||
|  |                 { | ||||||
|  |                     nread_elements = read_buffer_size; | ||||||
|  |                 } | ||||||
|  |             else | ||||||
|  |                 { | ||||||
|  |                     // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN | ||||||
|  |                     nread_elements = infile1.gcount(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             for (int index0 = 0; index0 < (nread_elements); index0 += 2) | ||||||
|  |                 { | ||||||
|  |                     // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands | ||||||
|  |                     dma_buffer[dma_index + dma_buff_offset_pos] = input_samples[index0]; | ||||||
|  |                     dma_buffer[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; | ||||||
|  |                     dma_index += 4; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             // read filename 1 (if enabled) | ||||||
|  |             if (num_input_files_ > 1) | ||||||
|  |                 { | ||||||
|  |                     dma_index = 0; | ||||||
|  |                     try | ||||||
|  |                         { | ||||||
|  |                             infile2.read(reinterpret_cast<char *>(input_samples.data()), read_buffer_size); | ||||||
|  |                         } | ||||||
|  |                     catch (const std::ifstream::failure &e) | ||||||
|  |                         { | ||||||
|  |                             std::cerr << "Exception reading file " << filename1_ << '\n'; | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     if (infile2) | ||||||
|  |                         { | ||||||
|  |                             nread_elements = read_buffer_size; | ||||||
|  |                         } | ||||||
|  |                     else | ||||||
|  |                         { | ||||||
|  |                             // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN | ||||||
|  |                             nread_elements = infile2.gcount(); | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                     for (int index0 = 0; index0 < (nread_elements); index0 += 2) | ||||||
|  |                         { | ||||||
|  |                             // filename2 is never the L1 band | ||||||
|  |                             dma_buffer[dma_index] = input_samples[index0]; | ||||||
|  |                             dma_buffer[dma_index + 1] = input_samples[index0 + 1]; | ||||||
|  |                             dma_index += 4; | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             if (nread_elements > 0) | ||||||
|  |                 { | ||||||
|  |                     if (dma_fpga->DMA_write(nread_elements * 2)) | ||||||
|  |                         { | ||||||
|  |                             std::cerr << "Error: DMA could not send all the required samples\n"; | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     // Throttle the DMA | ||||||
|  |                     std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             if (nbytes_remaining == 0) | ||||||
|  |                 { | ||||||
|  |                     if (repeat) | ||||||
|  |                         { | ||||||
|  |                             // read the file again | ||||||
|  |                             nbytes_remaining = samples * item_size; | ||||||
|  |                             read_buffer_size = sample_block_size * 2; | ||||||
|  |                             try | ||||||
|  |                                 { | ||||||
|  |                                     infile1.seekg(0); | ||||||
|  |                                 } | ||||||
|  |                             catch (const std::ifstream::failure &e) | ||||||
|  |                                 { | ||||||
|  |                                     std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n'; | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |  | ||||||
|  |                             // skip the initial samples if needed | ||||||
|  |                             uint64_t bytes_to_skeep = samples_to_skip * item_size; | ||||||
|  |                             try | ||||||
|  |                                 { | ||||||
|  |                                     infile1.ignore(bytes_to_skeep); | ||||||
|  |                                 } | ||||||
|  |                             catch (const std::ifstream::failure &e) | ||||||
|  |                                 { | ||||||
|  |                                     std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |  | ||||||
|  |                             if (!filename1_.empty()) | ||||||
|  |                                 { | ||||||
|  |                                     try | ||||||
|  |                                         { | ||||||
|  |                                             infile2.seekg(0); | ||||||
|  |                                         } | ||||||
|  |                                     catch (const std::ifstream::failure &e) | ||||||
|  |                                         { | ||||||
|  |                                             std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n'; | ||||||
|  |                                             break; | ||||||
|  |                                         } | ||||||
|  |  | ||||||
|  |                                     try | ||||||
|  |                                         { | ||||||
|  |                                             infile2.ignore(bytes_to_skeep); | ||||||
|  |                                         } | ||||||
|  |                                     catch (const std::ifstream::failure &e) | ||||||
|  |                                         { | ||||||
|  |                                             std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; | ||||||
|  |                                             break; | ||||||
|  |                                         } | ||||||
|  |                                 } | ||||||
|  |                         } | ||||||
|  |                     else | ||||||
|  |                         { | ||||||
|  |                             // the input file is completely processed. Stop the receiver. | ||||||
|  |                             run_DMA = false; | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |             std::unique_lock<std::mutex> lock_DMA(dma_mutex); | ||||||
|  |             if (enable_DMA_ == false) | ||||||
|  |                 { | ||||||
|  |                     run_DMA = false; | ||||||
|  |                 } | ||||||
|  |             lock_DMA.unlock(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (dma_fpga->DMA_close()) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Error closing loop device " << '\n'; | ||||||
|  |         } | ||||||
|  |     try | ||||||
|  |         { | ||||||
|  |             infile1.close(); | ||||||
|  |         } | ||||||
|  |     catch (const std::ifstream::failure &e) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Exception closing file " << filename0_ << '\n'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (num_input_files_ > 1) | ||||||
|  |         { | ||||||
|  |             try | ||||||
|  |                 { | ||||||
|  |                     infile2.close(); | ||||||
|  |                 } | ||||||
|  |             catch (const std::ifstream::failure &e) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Exception closing file " << filename1_ << '\n'; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // Stop the receiver | ||||||
|  |     queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMASignalSourceFPGA::run_dynamic_bit_selection_process() | ||||||
|  | { | ||||||
|  |     bool dynamic_bit_selection_active = true; | ||||||
|  |  | ||||||
|  |     while (dynamic_bit_selection_active) | ||||||
|  |         { | ||||||
|  |             // setting the bit selection to the top bits | ||||||
|  |             dynamic_bit_selection_fpga->bit_selection(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex); | ||||||
|  |             if (enable_dynamic_bit_selection_ == false) | ||||||
|  |                 { | ||||||
|  |                     dynamic_bit_selection_active = false; | ||||||
|  |                 } | ||||||
|  |             lock_dyn_bit_sel.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMASignalSourceFPGA::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMASignalSourceFPGA::disconnect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr DMASignalSourceFPGA::get_left_block() | ||||||
|  | { | ||||||
|  |     LOG(WARNING) << "Trying to get signal source left block."; | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr DMASignalSourceFPGA::get_right_block() | ||||||
|  | { | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
							
								
								
									
										118
									
								
								src/algorithms/signal_source/adapters/dma_signal_source_fpga.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/algorithms/signal_source/adapters/dma_signal_source_fpga.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | /*! | ||||||
|  |  * \file dma_signal_source_fpga.h | ||||||
|  |  * \brief signal source for a DMA connected directly to FPGA accelerators. | ||||||
|  |  * This source implements only the DMA control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * \author Marc Majoral, mmajoral(at)cttc.es | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H | ||||||
|  | #define GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H | ||||||
|  |  | ||||||
|  | #include "concurrent_queue.h" | ||||||
|  | #include "fpga_dma-proxy.h" | ||||||
|  | #include "fpga_dynamic_bit_selection.h" | ||||||
|  | #include "fpga_switch.h" | ||||||
|  | #include "gnss_block_interface.h" | ||||||
|  | #include "signal_source_base.h" | ||||||
|  | #include <pmt/pmt.h> | ||||||
|  | #include <cstdint> | ||||||
|  | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <string> | ||||||
|  | #include <thread> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \addtogroup Signal_Source | ||||||
|  |  * \{ */ | ||||||
|  | /** \addtogroup Signal_Source_adapters | ||||||
|  |  * \{ */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ConfigurationInterface; | ||||||
|  |  | ||||||
|  | class DMASignalSourceFPGA : public SignalSourceBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     DMASignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |         const std::string &role, unsigned int in_stream, | ||||||
|  |         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
|  |  | ||||||
|  |     ~DMASignalSourceFPGA(); | ||||||
|  |  | ||||||
|  |     void start() override; | ||||||
|  |  | ||||||
|  |     inline size_t item_size() override | ||||||
|  |     { | ||||||
|  |         return item_size_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void connect(gr::top_block_sptr top_block) override; | ||||||
|  |     void disconnect(gr::top_block_sptr top_block) override; | ||||||
|  |     gr::basic_block_sptr get_left_block() override; | ||||||
|  |     gr::basic_block_sptr get_right_block() override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector");  // Switch dhnamic bit selector device name | ||||||
|  |     const std::string empty_string; | ||||||
|  |     const uint64_t default_bandwidth = 12500000; | ||||||
|  |     // perform dynamic bit selection every 500 ms by default | ||||||
|  |     const uint32_t Gain_control_period_ms = 500; | ||||||
|  |     // sample block size when running in post-processing mode | ||||||
|  |     const int sample_block_size = 16384; | ||||||
|  |     const int32_t switch_to_DMA = 0; | ||||||
|  |  | ||||||
|  |     void run_DMA_process(const std::string &filename0, | ||||||
|  |         const std::string &filename1, | ||||||
|  |         uint64_t &samples_to_skip, | ||||||
|  |         size_t &item_size, | ||||||
|  |         int64_t &samples, | ||||||
|  |         bool &repeat, | ||||||
|  |         uint32_t &dma_buff_offset_pos, | ||||||
|  |         Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
|  |  | ||||||
|  |     void run_dynamic_bit_selection_process(); | ||||||
|  |  | ||||||
|  |     std::thread thread_file_to_dma; | ||||||
|  |     std::thread thread_dynamic_bit_selection; | ||||||
|  |  | ||||||
|  |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|  |     std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; | ||||||
|  |     std::shared_ptr<Fpga_DMA> dma_fpga; | ||||||
|  |  | ||||||
|  |     std::mutex dma_mutex; | ||||||
|  |     std::mutex dynamic_bit_selection_mutex; | ||||||
|  |  | ||||||
|  |     Concurrent_Queue<pmt::pmt_t> *queue_; | ||||||
|  |  | ||||||
|  |     std::string filename0_; | ||||||
|  |     std::string filename1_; | ||||||
|  |  | ||||||
|  |     uint64_t sample_rate_; | ||||||
|  |     uint64_t samples_to_skip_; | ||||||
|  |     int64_t samples_; | ||||||
|  |     uint32_t num_input_files_; | ||||||
|  |     uint32_t dma_buff_offset_pos_; | ||||||
|  |     uint32_t in_stream_; | ||||||
|  |     uint32_t out_stream_; | ||||||
|  |     size_t item_size_; | ||||||
|  |  | ||||||
|  |     bool enable_DMA_; | ||||||
|  |     bool enable_dynamic_bit_selection_; | ||||||
|  |     bool repeat_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \} */ | ||||||
|  | /** \} */ | ||||||
|  | #endif  // GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H | ||||||
| @@ -0,0 +1,347 @@ | |||||||
|  | /*! | ||||||
|  |  * \file fmcomms5_signal_source_fpga.cc | ||||||
|  |  * \brief signal source for the Analog Devices FMCOMMS5 directly connected | ||||||
|  |  * to the FPGA accelerators. | ||||||
|  |  * This source implements only the AD9361 control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * Please use the fmcomms2 source if conventional SDR acquisition and tracking | ||||||
|  |  * is selected in the configuration file. | ||||||
|  |  * \authors <ul> | ||||||
|  |  *          <li> Javier Arribas, jarribas(at)cttc.es | ||||||
|  |  *          <li> Marc Majoral, mmajoral(at)cttc.es | ||||||
|  |  *          </ul> | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "fmcomms5_signal_source_fpga.h" | ||||||
|  | #include "GPS_L1_CA.h" | ||||||
|  | #include "GPS_L5.h" | ||||||
|  | #include "ad9361_manager.h" | ||||||
|  | #include "configuration_interface.h" | ||||||
|  | #include "gnss_sdr_flags.h" | ||||||
|  | #include "gnss_sdr_string_literals.h" | ||||||
|  | #include <algorithm>  // for std::max | ||||||
|  | #include <chrono>     // for std::chrono | ||||||
|  | #include <cmath>      // for std::floor | ||||||
|  | #include <exception>  // for std::exception | ||||||
|  | #include <iostream>   // for std::cout | ||||||
|  |  | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  | #include <glog/logging.h> | ||||||
|  | #else | ||||||
|  | #include <absl/log/check.h> | ||||||
|  | #include <absl/log/log.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | using namespace std::string_literals; | ||||||
|  |  | ||||||
|  | Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||||
|  |     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) | ||||||
|  |     : SignalSourceBase(configuration, role, "FMCOMMS5_Signal_Source_FPGA"s), | ||||||
|  |       gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), | ||||||
|  |       gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), | ||||||
|  |       rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), | ||||||
|  |       filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), | ||||||
|  |       rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), | ||||||
|  |       rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), | ||||||
|  |       freq0_(configuration->property(role + ".freq0", static_cast<uint64_t>(GPS_L1_FREQ_HZ))), | ||||||
|  |       freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))), | ||||||
|  |       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), | ||||||
|  |       bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), | ||||||
|  |       Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))), | ||||||
|  |       Fstop_(configuration->property(role + ".Fstop", static_cast<float>(0.0))), | ||||||
|  |       in_stream_(in_stream), | ||||||
|  |       out_stream_(out_stream), | ||||||
|  |       item_size_(sizeof(int8_t)), | ||||||
|  |       filter_auto_(configuration->property(role + ".filter_auto", false)), | ||||||
|  |       quadrature_(configuration->property(role + ".quadrature", true)), | ||||||
|  |       rf_dc_(configuration->property(role + ".rf_dc", true)), | ||||||
|  |       bb_dc_(configuration->property(role + ".bb_dc", true)), | ||||||
|  |       rx1_enable_(configuration->property(role + ".rx1_enable", true)), | ||||||
|  |       rx2_enable_(configuration->property(role + ".rx2_enable", true)), | ||||||
|  |       enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), | ||||||
|  |       enable_ovf_check_buffer_monitor_active_(true), | ||||||
|  |       dump_(configuration->property(role + ".dump", false)), | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) | ||||||
|  | #else | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) | ||||||
|  | #endif | ||||||
|  | { | ||||||
|  |     const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_1B.count", 0) > 0)); | ||||||
|  |     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_L5.count", 0) > 0) || | ||||||
|  |                                (configuration->property("Channels_5X.count", 0) > 0)); | ||||||
|  |  | ||||||
|  |     const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; | ||||||
|  |  | ||||||
|  |     if (filter_auto_) | ||||||
|  |         { | ||||||
|  |             filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|  |     switch_fpga->set_switch_position(switch_to_real_time_mode); | ||||||
|  |  | ||||||
|  |     std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; | ||||||
|  |  | ||||||
|  |     // some basic checks | ||||||
|  |     if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; | ||||||
|  |             std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; | ||||||
|  |             std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; | ||||||
|  |             rf_port_select_ = default_rf_port_select; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; | ||||||
|  |             std::cout << " manual, slow_attack, fast_attack, hybrid\n"; | ||||||
|  |             std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; | ||||||
|  |             gain_mode_rx1_ = default_gain_mode; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; | ||||||
|  |             std::cout << " manual, slow_attack, fast_attack, hybrid\n"; | ||||||
|  |             std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; | ||||||
|  |             gain_mode_rx2_ = default_gain_mode; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (gain_mode_rx1_ == "manual") | ||||||
|  |         { | ||||||
|  |             if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; | ||||||
|  |                     std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; | ||||||
|  |                     rf_gain_rx1_ = default_manual_gain_rx1; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (gain_mode_rx2_ == "manual") | ||||||
|  |         { | ||||||
|  |             if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; | ||||||
|  |                     std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; | ||||||
|  |                     std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; | ||||||
|  |                     rf_gain_rx2_ = default_manual_gain_rx2; | ||||||
|  |                     LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter filter_source should take one of these values:\n"; | ||||||
|  |             std::cout << "  Off: Disable filter\n"; | ||||||
|  |             std::cout << "  Auto: Use auto-generated filters\n"; | ||||||
|  |             std::cout << "  File: User-provided filter in filter_filename parameter\n"; | ||||||
|  |             std::cout << "  Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; | ||||||
|  |             std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value filter_source=Off\n"; | ||||||
|  |             filter_source_ = std::string("Off"); | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (bandwidth_ < 200000 || bandwidth_ > 56000000) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; | ||||||
|  |             std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; | ||||||
|  |             bandwidth_ = default_bandwidth; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (enable_rx1_band) | ||||||
|  |         { | ||||||
|  |             std::cout << "LO 0 frequency : " << freq0_ << " Hz\n"; | ||||||
|  |         } | ||||||
|  |     if (enable_rx2_band) | ||||||
|  |         { | ||||||
|  |             std::cout << "LO 1 frequency : " << freq1_ << " Hz\n"; | ||||||
|  |         } | ||||||
|  |     try | ||||||
|  |         { | ||||||
|  |             config_ad9361_rx_local(bandwidth_, | ||||||
|  |                 sample_rate_, | ||||||
|  |                 freq0_, | ||||||
|  |                 freq1_, | ||||||
|  |                 rf_port_select_, | ||||||
|  |                 rx1_enable_, | ||||||
|  |                 rx2_enable_, | ||||||
|  |                 gain_mode_rx1_, | ||||||
|  |                 gain_mode_rx2_, | ||||||
|  |                 rf_gain_rx1_, | ||||||
|  |                 rf_gain_rx2_, | ||||||
|  |                 quadrature_, | ||||||
|  |                 rf_dc_, | ||||||
|  |                 bb_dc_, | ||||||
|  |                 filter_source_, | ||||||
|  |                 filter_filename_, | ||||||
|  |                 Fpass_, | ||||||
|  |                 Fstop_); | ||||||
|  |         } | ||||||
|  |     catch (const std::runtime_error &e) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); | ||||||
|  |  | ||||||
|  |     buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(num_freq_bands, dump_, dump_filename); | ||||||
|  |     thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // dynamic bits selection | ||||||
|  |     if (enable_dynamic_bit_selection_) | ||||||
|  |         { | ||||||
|  |             dynamic_bit_selection_fpga = std::make_shared<Fpga_dynamic_bit_selection>(enable_rx1_band, enable_rx2_band); | ||||||
|  |             thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (in_stream_ > 0) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "A signal source does not have an input stream"; | ||||||
|  |         } | ||||||
|  |     if (out_stream_ > 1) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "This implementation only supports one output stream"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Fmcomms5SignalSourceFPGA::~Fmcomms5SignalSourceFPGA() | ||||||
|  | { | ||||||
|  |     /* cleanup and exit */ | ||||||
|  |  | ||||||
|  |     if (rf_shutdown_) | ||||||
|  |         { | ||||||
|  |             std::cout << "* Disabling RX streaming channels\n"; | ||||||
|  |             if (!disable_ad9361_rx_local()) | ||||||
|  |                 { | ||||||
|  |                     LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // disable buffer overflow checking and buffer monitoring | ||||||
|  |     std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex); | ||||||
|  |     enable_ovf_check_buffer_monitor_active_ = false; | ||||||
|  |     lock_buffer_monitor.unlock(); | ||||||
|  |  | ||||||
|  |     if (thread_buffer_monitor.joinable()) | ||||||
|  |         { | ||||||
|  |             thread_buffer_monitor.join(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex); | ||||||
|  |     bool bit_selection_enabled = enable_dynamic_bit_selection_; | ||||||
|  |     lock_dyn_bit_sel.unlock(); | ||||||
|  |  | ||||||
|  |     if (bit_selection_enabled == true) | ||||||
|  |         { | ||||||
|  |             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); | ||||||
|  |             enable_dynamic_bit_selection_ = false; | ||||||
|  |             lock.unlock(); | ||||||
|  |  | ||||||
|  |             if (thread_dynamic_bit_selection.joinable()) | ||||||
|  |                 { | ||||||
|  |                     thread_dynamic_bit_selection.join(); | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Fmcomms5SignalSourceFPGA::run_dynamic_bit_selection_process() | ||||||
|  | { | ||||||
|  |     bool dynamic_bit_selection_active = true; | ||||||
|  |  | ||||||
|  |     while (dynamic_bit_selection_active) | ||||||
|  |         { | ||||||
|  |             // setting the bit selection to the top bits | ||||||
|  |             dynamic_bit_selection_fpga->bit_selection(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); | ||||||
|  |             if (enable_dynamic_bit_selection_ == false) | ||||||
|  |                 { | ||||||
|  |                     dynamic_bit_selection_active = false; | ||||||
|  |                 } | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process() | ||||||
|  | { | ||||||
|  |     bool enable_ovf_check_buffer_monitor_active = true; | ||||||
|  |  | ||||||
|  |     std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); | ||||||
|  |  | ||||||
|  |     while (enable_ovf_check_buffer_monitor_active) | ||||||
|  |         { | ||||||
|  |             buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); | ||||||
|  |             if (enable_ovf_check_buffer_monitor_active_ == false) | ||||||
|  |                 { | ||||||
|  |                     enable_ovf_check_buffer_monitor_active = false; | ||||||
|  |                 } | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Fmcomms5SignalSourceFPGA::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Fmcomms5SignalSourceFPGA::disconnect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr Fmcomms5SignalSourceFPGA::get_left_block() | ||||||
|  | { | ||||||
|  |     LOG(WARNING) << "Trying to get signal source left block."; | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr Fmcomms5SignalSourceFPGA::get_right_block() | ||||||
|  | { | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
| @@ -0,0 +1,135 @@ | |||||||
|  | /*! | ||||||
|  |  * \file fmcomms5_signal_source_fpga.h | ||||||
|  |  * \brief signal source for the Analog Devices FMCOMMS5 directly connected | ||||||
|  |  * to the FPGA accelerators. | ||||||
|  |  * This source implements only the AD9361 control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * Please use the fmcomms2 source if conventional SDR acquisition and tracking | ||||||
|  |  * is selected in the configuration file. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H | ||||||
|  | #define GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H | ||||||
|  |  | ||||||
|  | #include "concurrent_queue.h" | ||||||
|  | #include "fpga_buffer_monitor.h" | ||||||
|  | #include "fpga_dma-proxy.h" | ||||||
|  | #include "fpga_dynamic_bit_selection.h" | ||||||
|  | #include "fpga_switch.h" | ||||||
|  | #include "gnss_block_interface.h" | ||||||
|  | #include "signal_source_base.h" | ||||||
|  | #include <pmt/pmt.h> | ||||||
|  | #include <cstdint> | ||||||
|  | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <string> | ||||||
|  | #include <thread> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \addtogroup Signal_Source | ||||||
|  |  * \{ */ | ||||||
|  | /** \addtogroup Signal_Source_adapters | ||||||
|  |  * \{ */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ConfigurationInterface; | ||||||
|  |  | ||||||
|  | class Fmcomms5SignalSourceFPGA : public SignalSourceBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     Fmcomms5SignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |         const std::string &role, unsigned int in_stream, | ||||||
|  |         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
|  |  | ||||||
|  |     ~Fmcomms5SignalSourceFPGA(); | ||||||
|  |  | ||||||
|  |     inline size_t item_size() override | ||||||
|  |     { | ||||||
|  |         return item_size_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void connect(gr::top_block_sptr top_block) override; | ||||||
|  |     void disconnect(gr::top_block_sptr top_block) override; | ||||||
|  |     gr::basic_block_sptr get_left_block() override; | ||||||
|  |     gr::basic_block_sptr get_right_block() override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); | ||||||
|  |     const std::string default_rf_port_select = std::string("A_BALANCED"); | ||||||
|  |     const std::string default_gain_mode = std::string("slow_attack"); | ||||||
|  |     const double default_tx_attenuation_db = -10.0; | ||||||
|  |     const double default_manual_gain_rx1 = 64.0; | ||||||
|  |     const double default_manual_gain_rx2 = 64.0; | ||||||
|  |     const uint64_t default_bandwidth = 12500000; | ||||||
|  |  | ||||||
|  |     // perform dynamic bit selection every 500 ms by default | ||||||
|  |     const uint32_t Gain_control_period_ms = 500; | ||||||
|  |     // check buffer overflow and perform buffer monitoring every 1s by default | ||||||
|  |     const uint32_t buffer_monitor_period_ms = 1000; | ||||||
|  |     // buffer overflow and buffer monitoring initial delay | ||||||
|  |     const uint32_t buffer_monitoring_initial_delay_ms = 2000; | ||||||
|  |     // sample block size when running in post-processing mode | ||||||
|  |     const int sample_block_size = 16384; | ||||||
|  |     const int32_t switch_to_real_time_mode = 2; | ||||||
|  |  | ||||||
|  |     void run_dynamic_bit_selection_process(); | ||||||
|  |     void run_buffer_monitor_process(); | ||||||
|  |  | ||||||
|  |     std::thread thread_dynamic_bit_selection; | ||||||
|  |     std::thread thread_buffer_monitor; | ||||||
|  |  | ||||||
|  |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|  |     std::shared_ptr<Fpga_dynamic_bit_selection> dynamic_bit_selection_fpga; | ||||||
|  |     std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; | ||||||
|  |  | ||||||
|  |     std::mutex dynamic_bit_selection_mutex; | ||||||
|  |     std::mutex buffer_monitor_mutex; | ||||||
|  |  | ||||||
|  |     std::string gain_mode_rx1_; | ||||||
|  |     std::string gain_mode_rx2_; | ||||||
|  |     std::string rf_port_select_; | ||||||
|  |     std::string filter_file_; | ||||||
|  |     std::string filter_source_; | ||||||
|  |     std::string filter_filename_; | ||||||
|  |  | ||||||
|  |     double rf_gain_rx1_; | ||||||
|  |     double rf_gain_rx2_; | ||||||
|  |  | ||||||
|  |     uint64_t freq0_;  // frequency of local oscillator for ADRV9361-A | ||||||
|  |     uint64_t freq1_;  // frequency of local oscillator for ADRV9361-B | ||||||
|  |     uint64_t sample_rate_; | ||||||
|  |     uint64_t bandwidth_; | ||||||
|  |  | ||||||
|  |     float Fpass_; | ||||||
|  |     float Fstop_; | ||||||
|  |     uint32_t in_stream_; | ||||||
|  |     uint32_t out_stream_; | ||||||
|  |  | ||||||
|  |     size_t item_size_; | ||||||
|  |  | ||||||
|  |     bool filter_auto_; | ||||||
|  |     bool quadrature_; | ||||||
|  |     bool rf_dc_; | ||||||
|  |     bool bb_dc_; | ||||||
|  |     bool rx1_enable_; | ||||||
|  |     bool rx2_enable_; | ||||||
|  |     bool enable_dynamic_bit_selection_; | ||||||
|  |     bool enable_ovf_check_buffer_monitor_active_; | ||||||
|  |     bool dump_; | ||||||
|  |     bool rf_shutdown_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \} */ | ||||||
|  | /** \} */ | ||||||
|  | #endif  // GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H | ||||||
| @@ -0,0 +1,467 @@ | |||||||
|  | /*! | ||||||
|  |  * \file max2771_evkit_signal_source_fpga.cc | ||||||
|  |  * \brief Signal source for the MAX2771EVKIT evaluation board connected directly | ||||||
|  |  * to FPGA accelerators. | ||||||
|  |  * This source implements only the MAX2771 control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "max2771_evkit_signal_source_fpga.h" | ||||||
|  | #include "GPS_L1_CA.h" | ||||||
|  | #include "GPS_L2C.h" | ||||||
|  | #include "GPS_L5.h" | ||||||
|  | #include "configuration_interface.h" | ||||||
|  | #include "gnss_sdr_flags.h" | ||||||
|  | #include "gnss_sdr_string_literals.h" | ||||||
|  | #include <algorithm>  // for std::max | ||||||
|  | #include <chrono>     // for std::chrono | ||||||
|  | #include <cmath>      // for std::floor | ||||||
|  | #include <exception>  // for std::exception | ||||||
|  | #include <iostream>   // for std::cout | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  | #include <glog/logging.h> | ||||||
|  | #else | ||||||
|  | #include <absl/log/check.h> | ||||||
|  | #include <absl/log/log.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | using namespace std::string_literals; | ||||||
|  |  | ||||||
|  | MAX2771EVKITSignalSourceFPGA::MAX2771EVKITSignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||||
|  |     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) | ||||||
|  |     : SignalSourceBase(configuration, role, "MAX2771_EVKIT_Signal_Source_FPGA"s), | ||||||
|  |       freq_(configuration->property(role + ".freq", static_cast<uint64_t>(GPS_L1_FREQ_HZ))), | ||||||
|  |       sample_rate_(configuration->property(role + ".sampling_frequency", default_sampling_rate)), | ||||||
|  |       in_stream_(in_stream), | ||||||
|  |       out_stream_(out_stream), | ||||||
|  |       bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), | ||||||
|  |       filter_order_(configuration->property(role + ".filter_order", default_filter_order)), | ||||||
|  |       gain_in_(configuration->property(role + ".PGA_gain", default_PGA_gain_value)), | ||||||
|  |       item_size_(sizeof(int8_t)), | ||||||
|  |       chipen_(true), | ||||||
|  |       if_filter_gain_(configuration->property(role + ".enable_IF_filter_gain", true)), | ||||||
|  |       LNA_active_(configuration->property(role + ".LNA_active", false)), | ||||||
|  |       enable_agc_(configuration->property(role + ".enable_AGC", true)), | ||||||
|  |       enable_ovf_check_buffer_monitor_active_(true), | ||||||
|  |       dump_(configuration->property(role + ".dump", false)), | ||||||
|  | #if USE_GLOG_AND_GFLAGS | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) | ||||||
|  | #else | ||||||
|  |       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) | ||||||
|  | #endif | ||||||
|  | { | ||||||
|  |     // some basic checks | ||||||
|  |     if (freq_ != GPS_L1_FREQ_HZ and freq_ != GPS_L2_FREQ_HZ and freq_ != GPS_L5_FREQ_HZ) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter freq should take values " << GPS_L1_FREQ_HZ << ", " << GPS_L2_FREQ_HZ << ", or " << GPS_L5_FREQ_HZ << "\n"; | ||||||
|  |             std::cout << "Error: provided value freq = " << freq_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value freq = " << GPS_L1_FREQ_HZ << '\n'; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for freq parameter. Set to freq = " << GPS_L1_FREQ_HZ; | ||||||
|  |             freq_ = GPS_L1_FREQ_HZ; | ||||||
|  |         } | ||||||
|  |     if (sample_rate_ != 4092000 and sample_rate_ != 8184000 and sample_rate_ != 16368000 and sample_rate_ != 32736000) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter sampling_frequency should take values 4092000, 8184000, 16368000, or 32736000\n"; | ||||||
|  |             std::cout << "Error: provided value sampling_frequency = " << sample_rate_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value sampling_frequency = " << default_sampling_rate << '\n'; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for sampling_frequency parameter. Set to sampling_frequency = " << default_sampling_rate; | ||||||
|  |             sample_rate_ = default_sampling_rate; | ||||||
|  |         } | ||||||
|  |     if (bandwidth_ != 2500000 and bandwidth_ != 4200000 and bandwidth_ != 8700000 and bandwidth_ != 16400000 and bandwidth_ != 23400000 and bandwidth_ != 36000000) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter bandwidth can only take the following values: 2500000, 4200000, 8700000, 16400000, 23400000, and 36000000 Hz\n"; | ||||||
|  |             std::cout << "Error: provided value bandwidth = " << bandwidth_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value bandwidth = " << default_bandwidth << '\n'; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth = " << default_bandwidth; | ||||||
|  |             bandwidth_ = default_bandwidth; | ||||||
|  |         } | ||||||
|  |     if (filter_order_ != 3 and filter_order_ != 5) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter filter_order should take values 3 or 5\n"; | ||||||
|  |             std::cout << "Error: provided value filter_order = " << filter_order_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value filter_order = " << default_filter_order << '\n'; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for filter_order parameter. Set to filter_order = " << default_filter_order; | ||||||
|  |             filter_order_ = default_filter_order; | ||||||
|  |         } | ||||||
|  |     if (gain_in_ > max_PGA_gain_value) | ||||||
|  |         { | ||||||
|  |             std::cout << "Configuration parameter PGA_gain should be up to " << max_PGA_gain_value << "\n"; | ||||||
|  |             std::cout << "Error: provided value PGA_gain = " << gain_in_ << " is not among valid values\n"; | ||||||
|  |             std::cout << " This parameter has been set to its default value PGA_gain = " << default_PGA_gain_value << '\n'; | ||||||
|  |             LOG(WARNING) << "Invalid configuration value for PGA_gain parameter. Set to PGA_gain = " << default_PGA_gain_value; | ||||||
|  |             gain_in_ = default_PGA_gain_value; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::vector<uint32_t> register_values = setup_regs(); | ||||||
|  |  | ||||||
|  |     spidev_fpga = std::make_shared<Fpga_spidev>(); | ||||||
|  |  | ||||||
|  |     if (spidev_fpga->SPI_open()) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Cannot open SPI device\n"; | ||||||
|  |             // stop the receiver | ||||||
|  |             queue->push(pmt::make_any(command_event_make(200, 0))); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (configure(register_values)) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Error configuring the MAX2771 device " << '\n'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if (spidev_fpga->SPI_close()) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Error closing SPI device " << '\n'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); | ||||||
|  |  | ||||||
|  |     buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(NUM_FREQ_BANDS, dump_, dump_filename); | ||||||
|  |     thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); | ||||||
|  |  | ||||||
|  |     if (in_stream_ > 0) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "A signal source does not have an input stream"; | ||||||
|  |         } | ||||||
|  |     if (out_stream_ > 1) | ||||||
|  |         { | ||||||
|  |             LOG(ERROR) << "This implementation only supports one output stream"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::vector<uint32_t> MAX2771EVKITSignalSourceFPGA::setup_regs(void) | ||||||
|  | { | ||||||
|  |     std::vector<uint32_t> register_values = std::vector<uint32_t>(MAX2771_NUM_REGS); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     uint32_t LNA_mode = (LNA_active_) ? 0x0 : 0x2; | ||||||
|  |  | ||||||
|  |     uint32_t Filter_Bandwidth; | ||||||
|  |  | ||||||
|  |     switch (bandwidth_) | ||||||
|  |         { | ||||||
|  |         case 2500000: | ||||||
|  |             Filter_Bandwidth = 0x0; | ||||||
|  |             break; | ||||||
|  |         case 4200000: | ||||||
|  |             Filter_Bandwidth = 0x2; | ||||||
|  |             break; | ||||||
|  |         case 8700000: | ||||||
|  |             Filter_Bandwidth = 0x1; | ||||||
|  |             break; | ||||||
|  |         case 16400000: | ||||||
|  |             Filter_Bandwidth = 0x7; | ||||||
|  |             break; | ||||||
|  |         case 23400000: | ||||||
|  |             Filter_Bandwidth = 0x3; | ||||||
|  |             break; | ||||||
|  |         case 36000000: | ||||||
|  |             Filter_Bandwidth = 0x4; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             Filter_Bandwidth = 0x0;  // default bandwidth | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     uint32_t chipen_select = (chipen_) ? 0x1 : 0x0; | ||||||
|  |     uint32_t Filter_order_sel = (filter_order_ == 5) ? 0x0 : 0x1; | ||||||
|  |     uint32_t IF_filter_gain_sel = (if_filter_gain_) ? 0x1 : 0x0; | ||||||
|  |  | ||||||
|  |     register_values[0] =  // configuration 1 register | ||||||
|  |         (chipen_select << 31) + | ||||||
|  |         (IDLE << 30) + | ||||||
|  |         (0x8 << 26) +  // reserved | ||||||
|  |         (0x8 << 22) +  // reserved | ||||||
|  |         (0x2 << 20) +  // reserved | ||||||
|  |         (0x1 << 18) +  // reserved | ||||||
|  |         (MIXPOLE << 17) + | ||||||
|  |         (LNA_mode << 15) + | ||||||
|  |         (MIXERMODE << 13) + | ||||||
|  |         (FCEN << 6) + | ||||||
|  |         (Filter_Bandwidth << 3) + | ||||||
|  |         (Filter_order_sel << 2) + | ||||||
|  |         (FCENX << 1) + | ||||||
|  |         IF_filter_gain_sel; | ||||||
|  |  | ||||||
|  |     uint32_t AGC_mode = (enable_agc_) ? 0x0 : 0x2; | ||||||
|  |  | ||||||
|  |     register_values[1] =  // configuration 2 register | ||||||
|  |         (0x0 << 31) +     // reserved | ||||||
|  |         (0x1 << 29) +     // reserved | ||||||
|  |         (ANAIMON << 28) + | ||||||
|  |         (IQEN << 27) + | ||||||
|  |         (GAINREF << 15) + | ||||||
|  |         (SPI_SDIO_CONFIG << 13) + | ||||||
|  |         (AGC_mode << 11) + | ||||||
|  |         (FORMAT << 9) + | ||||||
|  |         (BITS << 6) + | ||||||
|  |         (DRVCFG << 4) + | ||||||
|  |         (0x1 << 3) +  // reserved | ||||||
|  |         (0x0 << 2) +  // reserved | ||||||
|  |         DIEID; | ||||||
|  |  | ||||||
|  |     register_values[2] =  // configuration 3 register | ||||||
|  |         (0x0 << 28) +     // reserved | ||||||
|  |         (gain_in_ << 22) + | ||||||
|  |         (0x1 << 21) +  // reserved | ||||||
|  |         (HILOADEN << 20) + | ||||||
|  |         (0x1 << 19) +  // reserved | ||||||
|  |         (0x1 << 18) +  // reserved | ||||||
|  |         (0x1 << 17) +  // reserved | ||||||
|  |         (0x1 << 16) +  // reserved | ||||||
|  |         (FHIPEN << 15) + | ||||||
|  |         (0x0 << 14) +  // reserved | ||||||
|  |         (PGAIEN << 13) + | ||||||
|  |         (PGAQEN << 12) + | ||||||
|  |         (STRMEN << 11) + | ||||||
|  |         (STRMSTART << 10) + | ||||||
|  |         (STRMSTOP << 9) + | ||||||
|  |         (0x7 << 6) +  // reserved | ||||||
|  |         (STRMBITS << 4) + | ||||||
|  |         (STAMPEN << 3) + | ||||||
|  |         (TIMESYNCEN << 2) + | ||||||
|  |         (DATASYNCEN << 1) + | ||||||
|  |         STRMRST; | ||||||
|  |  | ||||||
|  |     uint32_t clock_out_div_ratio; | ||||||
|  |  | ||||||
|  |     switch (sample_rate_) | ||||||
|  |         { | ||||||
|  |         case 4092000: | ||||||
|  |             clock_out_div_ratio = 0x1;  // XTAL frequency /4 | ||||||
|  |             break; | ||||||
|  |         case 8184000: | ||||||
|  |             clock_out_div_ratio = 0x2;  // XTAL frequency /2 | ||||||
|  |             break; | ||||||
|  |         case 16368000: | ||||||
|  |             clock_out_div_ratio = 0x3;  // XTAL frequency | ||||||
|  |             break; | ||||||
|  |         case 32736000: | ||||||
|  |             clock_out_div_ratio = 0x0;  // XTAL Frequency x2 | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             clock_out_div_ratio = 0x1;  // default XTAL frequency | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     register_values[3] =  // PLL configuration register | ||||||
|  |         (clock_out_div_ratio << 29) + | ||||||
|  |         (LOBAND << 28) + | ||||||
|  |         (0x1 << 27) +  // reserved | ||||||
|  |         (0x0 << 26) +  // reserved | ||||||
|  |         (0x0 << 25) +  // reserved | ||||||
|  |         (REFOUTEN << 24) + | ||||||
|  |         (0x1 << 23) +  // reserved | ||||||
|  |         (0x0 << 21) +  // reserved | ||||||
|  |         (IXTAL << 19) + | ||||||
|  |         (0x10 << 14) +  // reserved | ||||||
|  |         (0x0 << 13) +   // reserved | ||||||
|  |         (0x0 << 10) +   // reserved | ||||||
|  |         (ICP << 9) + | ||||||
|  |         (0x0 << 8) +  // reserved | ||||||
|  |         (0x0 << 7) +  // reserved | ||||||
|  |         (0x0 << 4) +  // reserved | ||||||
|  |         (INT_PLL << 3) + | ||||||
|  |         (PWRSAV << 2) + | ||||||
|  |         (0x0 << 1) +  // reserved | ||||||
|  |         0x0;          // reserved | ||||||
|  |  | ||||||
|  |     uint32_t freq_sel; | ||||||
|  |     switch (freq_) | ||||||
|  |         { | ||||||
|  |         case static_cast<uint64_t>(GPS_L1_FREQ_HZ): | ||||||
|  |             freq_sel = 0x604; | ||||||
|  |             break; | ||||||
|  |         case static_cast<uint64_t>(GPS_L2_FREQ_HZ): | ||||||
|  |             freq_sel = 0x4B0; | ||||||
|  |             break; | ||||||
|  |         case static_cast<uint64_t>(GPS_L5_FREQ_HZ): | ||||||
|  |             freq_sel = 0x47E; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             freq_sel = 0x604; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     register_values[4] =  // PLL integer division register | ||||||
|  |         (0x0 << 28) +     // reserved | ||||||
|  |         (freq_sel << 13) + | ||||||
|  |         (RDIV << 3) + | ||||||
|  |         0x0;  // reserved | ||||||
|  |  | ||||||
|  |     register_values[5] =  // PLL fractional division register | ||||||
|  |         (0x0 << 28) +     // reserved | ||||||
|  |         (FDIV << 8) + | ||||||
|  |         (0x7 << 4) +  // reserved | ||||||
|  |         (0x0 << 3) +  // reserved | ||||||
|  |         (0x0 << 2) +  // reserved | ||||||
|  |         (0x0 << 1) +  // reserved | ||||||
|  |         0x0;          // reserved | ||||||
|  |  | ||||||
|  |     register_values[6] =  // DSP interface register | ||||||
|  |         (0x0 << 28) +     // reserved | ||||||
|  |         0x8000000;        // reserved | ||||||
|  |  | ||||||
|  |     register_values[7] =  // clock configuration 1 register | ||||||
|  |         (0x0 << 29) +     // reserved | ||||||
|  |         (EXTADCCLK << 28) + | ||||||
|  |         (REFCLK_L_CNT << 16) + | ||||||
|  |         (REFCLK_M_CNT << 4) + | ||||||
|  |         (FCLKIN << 3) + | ||||||
|  |         (ADCCLK << 2) + | ||||||
|  |         (0x1 << 1) +  // reserved | ||||||
|  |         MODE; | ||||||
|  |  | ||||||
|  |     register_values[8] = TEST_MODE_1_REG_VAL;  // test mode 1 register | ||||||
|  |  | ||||||
|  |     register_values[9] = TEST_MODE_2_REG_VAL;  // test mode 2 register | ||||||
|  |  | ||||||
|  |     register_values[10] =  // clock configuration 2 register | ||||||
|  |         (0x0 << 29) +      // reserved | ||||||
|  |         (0x0 << 28) +      // reserved | ||||||
|  |         (ADCCLK_L_CNT << 16) + | ||||||
|  |         (ADCCLK_M_CNT << 4) + | ||||||
|  |         (PRE_FRACDIV_SEL << 3) + | ||||||
|  |         (CLKOUT_SEL << 2) + | ||||||
|  |         0x0;  // reserved | ||||||
|  |  | ||||||
|  |     return register_values; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool MAX2771EVKITSignalSourceFPGA::configure(std::vector<uint32_t> register_values) | ||||||
|  | { | ||||||
|  |     // write the registers | ||||||
|  |     std::cerr << "Configuring MAX2771 registers" << std::endl; | ||||||
|  |     uint32_t status = 0; | ||||||
|  |     for (uint32_t k = 0; k < register_values.size(); k++) | ||||||
|  |         { | ||||||
|  |             status = spidev_fpga->write_reg32(k, register_values[k]); | ||||||
|  |             if (status) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Error writing the MAX2771 registers" << std::endl; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // Read the registers and verify that the values are correctly written | ||||||
|  |     std::vector<uint32_t> reg_read = std::vector<uint32_t>(register_values.size()); | ||||||
|  |  | ||||||
|  |     for (uint8_t n = 0; n < register_values.size(); ++n) | ||||||
|  |         { | ||||||
|  |             status = spidev_fpga->read_reg32(n, ®_read[n]); | ||||||
|  |             if (status) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Error reading the MAX2771 registers" << std::endl; | ||||||
|  |                     return status; | ||||||
|  |                 } | ||||||
|  |             else | ||||||
|  |                 { | ||||||
|  |                     if (reg_read[n] != register_values[n]) | ||||||
|  |                         { | ||||||
|  |                             std::cerr << "Error: Failed to verify the MAX2771 registers " << std::endl; | ||||||
|  |                             return -1; | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA() | ||||||
|  | { | ||||||
|  |     /* cleanup and exit */ | ||||||
|  |  | ||||||
|  |     if (rf_shutdown_) | ||||||
|  |         { | ||||||
|  |             chipen_ = false; | ||||||
|  |             std::cout << "* MAX2771 Disabling RX streaming channels\n"; | ||||||
|  |             std::vector<uint32_t> register_values = setup_regs(); | ||||||
|  |  | ||||||
|  |             if (spidev_fpga->SPI_open()) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Cannot open SPI device\n"; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             if (configure(register_values)) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Error disabling the MAX2771 device " << '\n'; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             if (spidev_fpga->SPI_close()) | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Error closing SPI device " << '\n'; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // disable buffer overflow checking and buffer monitoring | ||||||
|  |     std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex); | ||||||
|  |     enable_ovf_check_buffer_monitor_active_ = false; | ||||||
|  |     lock_buffer_monitor.unlock(); | ||||||
|  |  | ||||||
|  |     if (thread_buffer_monitor.joinable()) | ||||||
|  |         { | ||||||
|  |             thread_buffer_monitor.join(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MAX2771EVKITSignalSourceFPGA::run_buffer_monitor_process() | ||||||
|  | { | ||||||
|  |     bool enable_ovf_check_buffer_monitor_active = true; | ||||||
|  |  | ||||||
|  |     std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); | ||||||
|  |  | ||||||
|  |     while (enable_ovf_check_buffer_monitor_active) | ||||||
|  |         { | ||||||
|  |             buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); | ||||||
|  |             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); | ||||||
|  |             if (enable_ovf_check_buffer_monitor_active_ == false) | ||||||
|  |                 { | ||||||
|  |                     enable_ovf_check_buffer_monitor_active = false; | ||||||
|  |                 } | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MAX2771EVKITSignalSourceFPGA::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MAX2771EVKITSignalSourceFPGA::disconnect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr MAX2771EVKITSignalSourceFPGA::get_left_block() | ||||||
|  | { | ||||||
|  |     LOG(WARNING) << "Trying to get signal source left block."; | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr MAX2771EVKITSignalSourceFPGA::get_right_block() | ||||||
|  | { | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
| @@ -0,0 +1,164 @@ | |||||||
|  | /*! | ||||||
|  |  * \file max2771_evkit_signal_source_fpga.h | ||||||
|  |  * \brief Signal source for the MAX2771EVKIT evaluation board connected directly | ||||||
|  |  * to FPGA accelerators. | ||||||
|  |  * This source implements only the MAX2771 control. It is NOT compatible with | ||||||
|  |  * conventional SDR acquisition and tracking blocks. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H | ||||||
|  | #define GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H | ||||||
|  |  | ||||||
|  | #include "command_event.h" | ||||||
|  | #include "concurrent_queue.h" | ||||||
|  | #include "fpga_buffer_monitor.h" | ||||||
|  | #include "fpga_spidev.h" | ||||||
|  | #include "gnss_block_interface.h" | ||||||
|  | #include "signal_source_base.h" | ||||||
|  | #include <pmt/pmt.h>  // for pmt::pmt_t | ||||||
|  | #include <cstdint>    // for fixed-width integer types | ||||||
|  | #include <memory>     // for smart pointers | ||||||
|  | #include <mutex>      // for mutex | ||||||
|  | #include <string>     // for strings | ||||||
|  | #include <thread>     // for threads | ||||||
|  | #include <vector>     // for std::vector | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \addtogroup Signal_Source | ||||||
|  |  * \{ */ | ||||||
|  | /** \addtogroup Signal_Source_adapters | ||||||
|  |  * \{ */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ConfigurationInterface; | ||||||
|  |  | ||||||
|  | class MAX2771EVKITSignalSourceFPGA : public SignalSourceBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     MAX2771EVKITSignalSourceFPGA(const ConfigurationInterface *configuration, | ||||||
|  |         const std::string &role, unsigned int in_stream, | ||||||
|  |         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
|  |  | ||||||
|  |     ~MAX2771EVKITSignalSourceFPGA(); | ||||||
|  |  | ||||||
|  |     std::vector<uint32_t> setup_regs(void); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     inline size_t item_size() override | ||||||
|  |     { | ||||||
|  |         return item_size_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void connect(gr::top_block_sptr top_block) override; | ||||||
|  |     void disconnect(gr::top_block_sptr top_block) override; | ||||||
|  |     gr::basic_block_sptr get_left_block() override; | ||||||
|  |     gr::basic_block_sptr get_right_block() override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); | ||||||
|  |     const uint64_t default_bandwidth = 2500000; | ||||||
|  |     const uint32_t default_filter_order = 5; | ||||||
|  |     const uint64_t default_sampling_rate = 4092000; | ||||||
|  |     const uint32_t default_PGA_gain_value = 0x3A;  // default PGA gain when AGC is off | ||||||
|  |     // max PGA gain value | ||||||
|  |     const uint32_t max_PGA_gain_value = 0x3F; | ||||||
|  |     // check buffer overflow and perform buffer monitoring every 1s by default | ||||||
|  |     const uint32_t buffer_monitor_period_ms = 1000; | ||||||
|  |     // buffer overflow and buffer monitoring initial delay | ||||||
|  |     const uint32_t buffer_monitoring_initial_delay_ms = 2000; | ||||||
|  |     // MAX2771 number of configuration registers | ||||||
|  |     const uint32_t MAX2771_NUM_REGS = 11; | ||||||
|  |     // MAX2771 configuration register fields | ||||||
|  |     const uint32_t NUM_FREQ_BANDS = 1; | ||||||
|  |     const uint32_t IDLE = 0x0;             // Idle mode disabled | ||||||
|  |     const uint32_t MIXPOLE = 0x0;          // set the passive filter pole at mixer output at 13 MHz. | ||||||
|  |     const uint32_t MIXERMODE = 0x0;        // L1 band enabled | ||||||
|  |     const uint32_t FCEN = 0x58;            // Center frequency not used when in low-pass filter mode. Set to default value. | ||||||
|  |     const uint32_t FCENX = 0x0;            // POlyphase filter selection set to Lowpass filter | ||||||
|  |     const uint32_t ANAIMON = 0x0;          // analog monitor disabled | ||||||
|  |     const uint32_t IQEN = 0x1;             // I and Q channels enable | ||||||
|  |     const uint32_t GAINREF = 0xAA;         // AGC Gain ref | ||||||
|  |     const uint32_t SPI_SDIO_CONFIG = 0x0;  // SPI SDIO config when tri-stated: nothing applied | ||||||
|  |     const uint32_t FORMAT = 0x1;           // sign and magnitude | ||||||
|  |     const uint32_t BITS = 0x2;             // number of bits in the ADC = 2 | ||||||
|  |     const uint32_t DRVCFG = 0x0;           // output driver configuration = CMOS Logic | ||||||
|  |     const uint32_t DIEID = 0x0;            // identifies version of IC | ||||||
|  |     const uint32_t HILOADEN = 0x0;         // disable output driver for high loads | ||||||
|  |     const uint32_t FHIPEN = 0x1;           // enable highpass coupling between filter and PGA. | ||||||
|  |     const uint32_t PGAIEN = 0x1;           // I-Channel PGA Enable | ||||||
|  |     const uint32_t PGAQEN = 0x1;           // Q-Channel PGA Enable | ||||||
|  |     const uint32_t STRMEN = 0x0;           // disable DSP interface for serial streaming of data | ||||||
|  |     const uint32_t STRMSTART = 0x0;        // the rising edge of this bit enables data streaming to the output, clock, data, sync and frame sync outputs. | ||||||
|  |     const uint32_t STRMSTOP = 0x0;         // the rising edge of this bit disables data streaming to the output, clock,  data sync and frame sync outputs. | ||||||
|  |     const uint32_t STRMBITS = 0x1;         // number of bits to be streamed: I MSB, I LSB | ||||||
|  |     const uint32_t STAMPEN = 0x1;          // enable frame number insertion | ||||||
|  |     const uint32_t TIMESYNCEN = 0x1;       // enable the output of the time sync pulses at all times when streaming is enabled. | ||||||
|  |     const uint32_t DATASYNCEN = 0x0;       // disable the sync pulses at the DATASYNC output | ||||||
|  |     const uint32_t STRMRST = 0x0;          // counter reset not active | ||||||
|  |     const uint32_t LOBAND = 0x0;           // L1 band | ||||||
|  |     const uint32_t REFOUTEN = 0x1;         // Output clock buffer enable | ||||||
|  |     const uint32_t IXTAL = 0x1;            // XTAL osscillator/buffer set to normal current | ||||||
|  |     const uint32_t ICP = 0x0;              // charge pump current selection set to 0.5 mA | ||||||
|  |     const uint32_t INT_PLL = 0x1;          // PLL mode set to integer-N PLL | ||||||
|  |     const uint32_t PWRSAV = 0x0;           // PLL power save mode disabled | ||||||
|  |     const uint32_t RDIV = 0x10;            // Set the PLL reference division ratio such that the L1 band is tuned to 1575.42 Mhz | ||||||
|  |     const uint32_t FDIV = 0x80000;         // PLL fractional division ratio not used. Set to default value | ||||||
|  |     const uint32_t EXTADCCLK = 0x0;        // use internally generated clock | ||||||
|  |     const uint32_t REFCLK_L_CNT = 0x100;   // set the L counter of the reference clock configuration to its default value | ||||||
|  |     const uint32_t REFCLK_M_CNT = 0x61B;   // set the M counter of the reference clock configuration to its default value | ||||||
|  |     const uint32_t FCLKIN = 0x0;           // fractional clock divider set to default value | ||||||
|  |     const uint32_t ADCCLK = 0x0;           // ADC clock selection set to reference clock divider/multiplier | ||||||
|  |     const uint32_t MODE = 0x0;             // DSP interface mode selection | ||||||
|  |     const uint32_t ADCCLK_L_CNT = 0x100;   // set the L counter of the ADC clock configuration to its default value | ||||||
|  |     const uint32_t ADCCLK_M_CNT = 0x61B;   // set the M counter of the ADC clock configuration to its default value | ||||||
|  |     const uint32_t PRE_FRACDIV_SEL = 0x0;  // bypass fractional clock divider | ||||||
|  |     const uint32_t CLKOUT_SEL = 0x1;       // CLKOUT selection set to ADC clock | ||||||
|  |     // MAX2771 configuration register registers | ||||||
|  |     const uint32_t TEST_MODE_1_REG_VAL = 0x01E0F401;  // reserved | ||||||
|  |     const uint32_t TEST_MODE_2_REG_VAL = 0x00000002; | ||||||
|  |  | ||||||
|  |     bool configure(std::vector<uint32_t> register_values); | ||||||
|  |     void run_buffer_monitor_process(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     std::thread thread_buffer_monitor; | ||||||
|  |  | ||||||
|  |     std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga; | ||||||
|  |     std::shared_ptr<Fpga_spidev> spidev_fpga; | ||||||
|  |  | ||||||
|  |     std::mutex buffer_monitor_mutex; | ||||||
|  |  | ||||||
|  |     uint64_t freq_;  // frequency of local oscillator | ||||||
|  |     uint64_t sample_rate_; | ||||||
|  |  | ||||||
|  |     uint32_t in_stream_; | ||||||
|  |     uint32_t out_stream_; | ||||||
|  |     uint32_t bandwidth_;     // 2500000, 4200000, 8700000, 16400000, 23400000, 36000000 | ||||||
|  |     uint32_t filter_order_;  // 3, 5 | ||||||
|  |     uint32_t gain_in_;       // 0 to 0x3F | ||||||
|  |  | ||||||
|  |     size_t item_size_;  // 1 | ||||||
|  |  | ||||||
|  |     bool chipen_;          // chip enable | ||||||
|  |     bool if_filter_gain_;  // true, false | ||||||
|  |     bool LNA_active_;      // true, false | ||||||
|  |     bool enable_agc_;      // true, false | ||||||
|  |     bool enable_ovf_check_buffer_monitor_active_; | ||||||
|  |     bool dump_; | ||||||
|  |     bool rf_shutdown_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** \} */ | ||||||
|  | /** \} */ | ||||||
|  | #endif  // GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H | ||||||
| @@ -12,17 +12,27 @@ if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) | |||||||
|     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if(ENABLE_FPGA OR ENABLE_AD9361) | if(ENABLE_MAX2771) | ||||||
|  |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc) | ||||||
|  |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.h) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_FPGA) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc) |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h) |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc) |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h) |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc) | endif() | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) |  | ||||||
|  | if(ENABLE_DMA_PROXY) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc) |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h) |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | if((ENABLE_FPGA AND ENABLE_AD9361) OR ENABLE_MAX2771) | ||||||
|  |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc) | ||||||
|  |     set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(ENABLE_PLUTOSDR) | if(ENABLE_PLUTOSDR) | ||||||
|     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) |     set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ | |||||||
| #include "fpga_buffer_monitor.h" | #include "fpga_buffer_monitor.h" | ||||||
| #include "gnss_sdr_create_directory.h" | #include "gnss_sdr_create_directory.h" | ||||||
| #include "gnss_sdr_filesystem.h" | #include "gnss_sdr_filesystem.h" | ||||||
|  | #include "uio_fpga.h" | ||||||
| #include <ctime>       // for time, localtime | #include <ctime>       // for time, localtime | ||||||
| #include <fcntl.h>     // for open, O_RDWR, O_SYNC | #include <fcntl.h>     // for open, O_RDWR, O_SYNC | ||||||
| #include <fstream>     // for string, ofstream | #include <fstream>     // for string, ofstream | ||||||
| @@ -40,7 +41,7 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, | Fpga_buffer_monitor::Fpga_buffer_monitor( | ||||||
|     uint32_t num_freq_bands, |     uint32_t num_freq_bands, | ||||||
|     bool dump, |     bool dump, | ||||||
|     std::string dump_filename) |     std::string dump_filename) | ||||||
| @@ -50,10 +51,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, | |||||||
|       d_max_buff_occ_freq_band_1(0), |       d_max_buff_occ_freq_band_1(0), | ||||||
|       d_dump(dump) |       d_dump(dump) | ||||||
| { | { | ||||||
|     // open device descriptor |     std::string device_io_name; | ||||||
|     if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) |  | ||||||
|  |     // find the uio device file corresponding to the buffer monitor | ||||||
|  |     if (find_uio_dev_file_name(device_io_name, BUFFER_MONITOR_DEVICE_NAME, 0) < 0) | ||||||
|         { |         { | ||||||
|             LOG(WARNING) << "Cannot open deviceio" << device_name; |             std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << BUFFER_MONITOR_DEVICE_NAME << '\n'; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // open device descriptor | ||||||
|  |     if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1) | ||||||
|  |         { | ||||||
|  |             LOG(WARNING) << "Cannot open deviceio" << device_io_name; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     // device memory map |     // device memory map | ||||||
|   | |||||||
| @@ -45,10 +45,13 @@ public: | |||||||
|     /*! |     /*! | ||||||
|      * \brief Constructor |      * \brief Constructor | ||||||
|      */ |      */ | ||||||
|     explicit Fpga_buffer_monitor(const std::string& device_name, |     explicit Fpga_buffer_monitor(uint32_t num_freq_bands, | ||||||
|         uint32_t num_freq_bands, |  | ||||||
|         bool dump, |         bool dump, | ||||||
|         std::string dump_filename); |         std::string dump_filename); | ||||||
|  |     //    explicit Fpga_buffer_monitor(const std::string& device_name, | ||||||
|  |     //        uint32_t num_freq_bands, | ||||||
|  |     //        bool dump, | ||||||
|  |     //        std::string dump_filename); | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Destructor |      * \brief Destructor | ||||||
| @@ -61,6 +64,7 @@ public: | |||||||
|     void check_buffer_overflow_and_monitor_buffer_status(); |     void check_buffer_overflow_and_monitor_buffer_status(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     const std::string BUFFER_MONITOR_DEVICE_NAME = std::string("buffer_monitor");  // buffer monitor device name | ||||||
|     static const size_t FPGA_PAGE_SIZE = 0x1000; |     static const size_t FPGA_PAGE_SIZE = 0x1000; | ||||||
|     static const uint32_t test_register_writeval = 0x55AA; |     static const uint32_t test_register_writeval = 0x55AA; | ||||||
|     static const uint32_t num_sapmples_per_buffer_element = 2; |     static const uint32_t num_sapmples_per_buffer_element = 2; | ||||||
|   | |||||||
| @@ -56,7 +56,6 @@ public: | |||||||
|     void bit_selection(void); |     void bit_selection(void); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0");          // Switch UIO device name |  | ||||||
|     const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector");  // Switch dhnamic bit selector device name |     const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector");  // Switch dhnamic bit selector device name | ||||||
|     static const size_t FPGA_PAGE_SIZE = 0x1000; |     static const size_t FPGA_PAGE_SIZE = 0x1000; | ||||||
|     static const uint32_t Num_bits_ADC = 12;                                      // Number of bits in the ADC |     static const uint32_t Num_bits_ADC = 12;                                      // Number of bits in the ADC | ||||||
|   | |||||||
							
								
								
									
										131
									
								
								src/algorithms/signal_source/libs/fpga_spidev.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/algorithms/signal_source/libs/fpga_spidev.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | |||||||
|  | /*! | ||||||
|  |  * \file fpga_spidev.cc | ||||||
|  |  * \brief FPGA SPI control. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "fpga_spidev.h" | ||||||
|  | #include <cstring>             // for memset() | ||||||
|  | #include <fcntl.h>             // for open(), O_RDWR | ||||||
|  | #include <iostream>            // for std::cerr | ||||||
|  | #include <linux/spi/spidev.h>  // spidev driver | ||||||
|  | #include <sys/ioctl.h>         // for ioctl() | ||||||
|  | #include <unistd.h>            // for close() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int Fpga_spidev::SPI_open() | ||||||
|  | { | ||||||
|  |     if ((d_fd = open(SPI_DEVICE_NAME.c_str(), O_RDWR)) < 0) | ||||||
|  |         { | ||||||
|  |             std::cerr << "Failed to open the " << SPI_DEVICE_NAME << " device file \n"; | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     int ret; | ||||||
|  |     int32_t mode = 0; | ||||||
|  |  | ||||||
|  |     ret = ioctl(d_fd, SPI_IOC_WR_MODE32, &mode); | ||||||
|  |     if (ret == -1) | ||||||
|  |         { | ||||||
|  |             std::cerr << "can't set spi mode\n"; | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     ret = ioctl(d_fd, SPI_IOC_RD_MODE32, &mode);  // le digo al spi "algo" | ||||||
|  |     if (ret == -1) | ||||||
|  |         { | ||||||
|  |             std::cerr << "can't set spi mode\n"; | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int Fpga_spidev::write_reg32(char addr, uint32_t data) | ||||||
|  | { | ||||||
|  |     uint8_t data_buffer[2]; | ||||||
|  |     uint8_t recv_buffer[4]; | ||||||
|  |     int res = 0; | ||||||
|  |     struct spi_ioc_transfer xfer[2]; | ||||||
|  |     memset(xfer, 0, sizeof(xfer)); | ||||||
|  |     xfer[0].bits_per_word = 8; | ||||||
|  |     xfer[0].speed_hz = SPI_SPEED; | ||||||
|  |     xfer[1].bits_per_word = 8; | ||||||
|  |     xfer[1].speed_hz = SPI_SPEED; | ||||||
|  |  | ||||||
|  |     memset(&recv_buffer, 0, sizeof(recv_buffer)); | ||||||
|  |     memset(&data_buffer, 0, sizeof(data_buffer)); | ||||||
|  |  | ||||||
|  |     data_buffer[1] = addr << 4 | 0 << 3; | ||||||
|  |     xfer[0].tx_buf = (unsigned long)data_buffer; | ||||||
|  |     xfer[0].len = 2; | ||||||
|  |  | ||||||
|  |     // Would use memcpy but 'data' is in little endian | ||||||
|  |     ((char*)recv_buffer)[0] = ((char*)&data)[3]; | ||||||
|  |     ((char*)recv_buffer)[1] = ((char*)&data)[2]; | ||||||
|  |     ((char*)recv_buffer)[2] = ((char*)&data)[1]; | ||||||
|  |     ((char*)recv_buffer)[3] = ((char*)&data)[0]; | ||||||
|  |  | ||||||
|  |     xfer[1].tx_buf = (unsigned long)recv_buffer; | ||||||
|  |     xfer[1].len = 4; | ||||||
|  |     res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer); | ||||||
|  |     if (res < 0) | ||||||
|  |         { | ||||||
|  |             std::cout << "Error sending SPI message\n"; | ||||||
|  |             return res; | ||||||
|  |         } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int Fpga_spidev::read_reg32(uint8_t addr, uint32_t* copy_to) | ||||||
|  | { | ||||||
|  |     uint8_t data_buffer[2]; | ||||||
|  |     uint8_t recv_buffer[4]; | ||||||
|  |     int res; | ||||||
|  |     struct spi_ioc_transfer xfer[2]; | ||||||
|  |     memset(xfer, 0, sizeof(xfer)); | ||||||
|  |     xfer[0].bits_per_word = 8; | ||||||
|  |     xfer[0].speed_hz = SPI_SPEED; | ||||||
|  |     xfer[1].bits_per_word = 8; | ||||||
|  |     xfer[1].speed_hz = SPI_SPEED; | ||||||
|  |  | ||||||
|  |     memset(&recv_buffer, 0, sizeof(recv_buffer)); | ||||||
|  |     memset(&data_buffer, 0, sizeof(data_buffer)); | ||||||
|  |  | ||||||
|  |     data_buffer[1] = addr << 4 | 1 << 3; | ||||||
|  |     xfer[0].tx_buf = (unsigned long)data_buffer; | ||||||
|  |     xfer[0].len = 2; | ||||||
|  |  | ||||||
|  |     xfer[1].rx_buf = (unsigned long)recv_buffer; | ||||||
|  |     xfer[1].len = 4; | ||||||
|  |     res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer); | ||||||
|  |     if (res < 0) | ||||||
|  |         { | ||||||
|  |             std::cout << "Error sending SPI message\n"; | ||||||
|  |             return res; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // the register data is received in the reverse order | ||||||
|  |     uint32_t tmp_result = 0; | ||||||
|  |     for (uint32_t k = 0; k < 4; ++k) | ||||||
|  |         { | ||||||
|  |             tmp_result = tmp_result + ((recv_buffer[3 - k]) << 8 * k); | ||||||
|  |         } | ||||||
|  |     *copy_to = tmp_result; | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int Fpga_spidev::SPI_close() const | ||||||
|  | { | ||||||
|  |     return close(d_fd); | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								src/algorithms/signal_source/libs/fpga_spidev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/algorithms/signal_source/libs/fpga_spidev.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | /*! | ||||||
|  |  * \file fpga_spidev.h | ||||||
|  |  * \brief FPGA SPI control. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. | ||||||
|  |  * This file is part of GNSS-SDR. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2024  (see AUTHORS file for a list of contributors) | ||||||
|  |  * SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GNSS_SDR_FPGA_SPIDEV_H | ||||||
|  | #define GNSS_SDR_FPGA_SPIDEV_H | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | class Fpga_spidev | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     /*! | ||||||
|  |      * \brief Default constructor. | ||||||
|  |      */ | ||||||
|  |     Fpga_spidev() = default; | ||||||
|  |  | ||||||
|  |     /*! | ||||||
|  |      * \brief Default destructor. | ||||||
|  |      */ | ||||||
|  |     ~Fpga_spidev() = default; | ||||||
|  |  | ||||||
|  |     /*! | ||||||
|  |      * \brief write a register through the SPI. | ||||||
|  |      */ | ||||||
|  |     int write_reg32(char addr, uint32_t data); | ||||||
|  |  | ||||||
|  |     /*! | ||||||
|  |      * \brief read a register through the SPI. | ||||||
|  |      */ | ||||||
|  |     int read_reg32(uint8_t addr, uint32_t* copy_to); | ||||||
|  |     /*! | ||||||
|  |      * \brief Open the SPI device driver. | ||||||
|  |      */ | ||||||
|  |     int SPI_open(void); | ||||||
|  |  | ||||||
|  |     /*! | ||||||
|  |      * \brief Close the SPI device driver | ||||||
|  |      */ | ||||||
|  |     int SPI_close(void) const; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     static const uint32_t SPI_SPEED = 250000; | ||||||
|  |     const std::string SPI_DEVICE_NAME = std::string("/dev/spidev2.0");  // Switch UIO device name | ||||||
|  |  | ||||||
|  |     int d_fd; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif  // GNSS_SDR_FPGA_SPIDEV_H | ||||||
| @@ -21,6 +21,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "fpga_switch.h" | #include "fpga_switch.h" | ||||||
|  | #include "uio_fpga.h" | ||||||
| #include <fcntl.h>     // for open, O_RDWR, O_SYNC | #include <fcntl.h>     // for open, O_RDWR, O_SYNC | ||||||
| #include <iostream>    // for cout | #include <iostream>    // for cout | ||||||
| #include <sys/mman.h>  // for mmap | #include <sys/mman.h>  // for mmap | ||||||
| @@ -32,11 +33,19 @@ | |||||||
| #include <absl/log/log.h> | #include <absl/log/log.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| Fpga_Switch::Fpga_Switch(const std::string &device_name) | Fpga_Switch::Fpga_Switch(void) | ||||||
| { | { | ||||||
|     if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) |     std::string device_io_name;  // Switch UIO device file | ||||||
|  |     // find the uio device file corresponding to the switch. | ||||||
|  |     if (find_uio_dev_file_name(device_io_name, SWITCH_DEVICE_NAME, 0) < 0) | ||||||
|         { |         { | ||||||
|             LOG(WARNING) << "Cannot open deviceio" << device_name; |             std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << SWITCH_DEVICE_NAME << '\n'; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1) | ||||||
|  |         { | ||||||
|  |             LOG(WARNING) << "Cannot open deviceio" << device_io_name; | ||||||
|         } |         } | ||||||
|     d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE, |     d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE, | ||||||
|         PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); |         PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); | ||||||
|   | |||||||
| @@ -42,8 +42,7 @@ public: | |||||||
|     /*! |     /*! | ||||||
|      * \brief Constructor |      * \brief Constructor | ||||||
|      */ |      */ | ||||||
|     explicit Fpga_Switch(const std::string& device_name); |     Fpga_Switch(void); | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Destructor |      * \brief Destructor | ||||||
|      */ |      */ | ||||||
| @@ -55,6 +54,7 @@ public: | |||||||
|     void set_switch_position(int32_t switch_position); |     void set_switch_position(int32_t switch_position); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     const std::string SWITCH_DEVICE_NAME = std::string("AXIS_Switch_v1_0_0");  // Switch UIO device name | ||||||
|     static const size_t FPGA_PAGE_SIZE = 0x1000; |     static const size_t FPGA_PAGE_SIZE = 0x1000; | ||||||
|     static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; |     static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; | ||||||
|     static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50; |     static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50; | ||||||
|   | |||||||
| @@ -65,11 +65,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga" |      * \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga"; |         return "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -59,11 +59,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "Galileo_E5a_DLL_PLL_Tracking_Fpga" |      * \brief Returns "Galileo_E5a_DLL_PLL_Tracking_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "Galileo_E5a_DLL_PLL_Tracking_Fpga"; |         return "Galileo_E5a_DLL_PLL_Tracking_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -64,11 +64,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_Fpga" |      * \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; |         return "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -57,10 +57,10 @@ public: | |||||||
|         return role_; |         return role_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     //! Returns "GPS_L2_M_DLL_PLL_Tracking_Fpga" |     //! Returns "GPS_L2_M_DLL_PLL_Tracking_FPGA" | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L2_M_DLL_PLL_Tracking_Fpga"; |         return "GPS_L2_M_DLL_PLL_Tracking_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline size_t item_size() override |     inline size_t item_size() override | ||||||
|   | |||||||
| @@ -65,11 +65,11 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|      * \brief Returns "GPS_L5_DLL_PLL_Tracking_Fpga" |      * \brief Returns "GPS_L5_DLL_PLL_Tracking_FPGA" | ||||||
|      */ |      */ | ||||||
|     inline std::string implementation() override |     inline std::string implementation() override | ||||||
|     { |     { | ||||||
|         return "GPS_L5_DLL_PLL_Tracking_Fpga"; |         return "GPS_L5_DLL_PLL_Tracking_FPGA"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*! |     /*! | ||||||
|   | |||||||
| @@ -98,6 +98,14 @@ if(ENABLE_AD9361) | |||||||
|     target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1) |     target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_MAX2771) | ||||||
|  |     target_compile_definitions(core_receiver PRIVATE -DMAX2771_DRIVER=1) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_DMA_PROXY) | ||||||
|  |     target_compile_definitions(core_receiver PRIVATE -DDMA_PROXY_DRIVER=1) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(ENABLE_OSMOSDR) | if(ENABLE_OSMOSDR) | ||||||
|     if(GROSMOSDR_FOUND) |     if(GROSMOSDR_FOUND) | ||||||
|         target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1) |         target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1) | ||||||
|   | |||||||
| @@ -167,8 +167,17 @@ | |||||||
| #include "fmcomms2_signal_source.h" | #include "fmcomms2_signal_source.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if AD9361_DRIVER | #if ENABLE_FPGA and AD9361_DRIVER | ||||||
| #include "ad9361_fpga_signal_source.h" | #include "adrv9361_z7035_signal_source_fpga.h" | ||||||
|  | #include "fmcomms5_signal_source_fpga.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if MAX2771_DRIVER | ||||||
|  | #include "max2771_evkit_signal_source_fpga.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if DMA_PROXY_DRIVER | ||||||
|  | #include "dma_signal_source_fpga.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if LIMESDR_DRIVER | #if LIMESDR_DRIVER | ||||||
| @@ -812,12 +821,34 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock( | |||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if AD9361_DRIVER | #if ENABLE_FPGA and AD9361_DRIVER | ||||||
|             // The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver |             else if (implementation == "ADRV9361_Z7035_Signal_Source_FPGA") | ||||||
|             // in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver. |  | ||||||
|             else if (implementation == "Ad9361_Fpga_Signal_Source") |  | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Ad9361FpgaSignalSource>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Adrv9361z7035SignalSourceFPGA>(configuration, role, in_streams, | ||||||
|  |                         out_streams, queue); | ||||||
|  |                     block = std::move(block_); | ||||||
|  |                 } | ||||||
|  |             else if (implementation == "FMCOMMS5_Signal_Source_FPGA") | ||||||
|  |                 { | ||||||
|  |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Fmcomms5SignalSourceFPGA>(configuration, role, in_streams, | ||||||
|  |                         out_streams, queue); | ||||||
|  |                     block = std::move(block_); | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if ENABLE_FPGA and MAX2771_DRIVER | ||||||
|  |             else if (implementation == "MAX2771_EVKIT_Signal_Source_FPGA") | ||||||
|  |                 { | ||||||
|  |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<MAX2771EVKITSignalSourceFPGA>(configuration, role, in_streams, | ||||||
|  |                         out_streams, queue); | ||||||
|  |                     block = std::move(block_); | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if ENABLE_FPGA and DMA_PROXY_DRIVER | ||||||
|  |             else if (implementation == "DMA_Signal_Source_FPGA") | ||||||
|  |                 { | ||||||
|  |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<DMASignalSourceFPGA>(configuration, role, in_streams, | ||||||
|                         out_streams, queue); |                         out_streams, queue); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
| @@ -1054,31 +1085,31 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock( | |||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|             else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") |             else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") |             else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") |             else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") |             else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, |                     std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") |             else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
| @@ -1204,31 +1235,31 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock( | |||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|             else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |             else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, |                     std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |             else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, |                     std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") |             else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) |             else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
|                     block = std::move(block_); |                     block = std::move(block_); | ||||||
|                 } |                 } | ||||||
|             else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |             else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|                 { |                 { | ||||||
|                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                         out_streams); |                         out_streams); | ||||||
| @@ -1492,31 +1523,31 @@ std::unique_ptr<AcquisitionInterface> GNSSBlockFactory::GetAcqBlock( | |||||||
|         } |         } | ||||||
| #endif | #endif | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|     else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") |     else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, |             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL1CaPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") |     else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, |             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE1PcpsAmbiguousAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") |     else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, |             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL2MPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") |     else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, |             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GpsL5iPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") |     else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, |             std::unique_ptr<AcquisitionInterface> block_ = std::make_unique<GalileoE5aPcpsAcquisitionFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
| @@ -1660,31 +1691,31 @@ std::unique_ptr<TrackingInterface> GNSSBlockFactory::GetTrkBlock( | |||||||
|         } |         } | ||||||
| #endif | #endif | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|     else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, |             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL1CaDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, |             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE1DllPllVemlTrackingFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, |             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL2MDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) |     else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) | ||||||
|         { |         { | ||||||
|             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, |             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GpsL5DllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|             block = std::move(block_); |             block = std::move(block_); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, |             std::unique_ptr<TrackingInterface> block_ = std::make_unique<GalileoE5aDllPllTrackingFpga>(configuration, role, in_streams, | ||||||
|                 out_streams); |                 out_streams); | ||||||
|   | |||||||
| @@ -554,7 +554,7 @@ int GNSSFlowgraph::connect_fpga_flowgraph() | |||||||
|             if (src == nullptr) |             if (src == nullptr) | ||||||
|                 { |                 { | ||||||
|                     help_hint_ += " * Check implementation name for SignalSource block.\n"; |                     help_hint_ += " * Check implementation name for SignalSource block.\n"; | ||||||
|                     help_hint_ += "   Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source\n"; |                     help_hint_ += "   Signal Source block implementation for FPGA off-loading should be Ad9361_Signal_Source_Fpga or Fpga_DMA_2Signal_Source\n"; | ||||||
|                     return 1; |                     return 1; | ||||||
|                 } |                 } | ||||||
|             if (src->item_size() == 0) |             if (src->item_size() == 0) | ||||||
|   | |||||||
| @@ -67,7 +67,7 @@ class GalileoE1PcpsAmbiguousAcquisitionTestFpga : public ::testing::Test | |||||||
| { | { | ||||||
| public: | public: | ||||||
|     bool acquire_signal(); |     bool acquire_signal(); | ||||||
|     std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; |     std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; | ||||||
|     std::vector<Gnss_Synchro> gnss_synchro_vec; |     std::vector<Gnss_Synchro> gnss_synchro_vec; | ||||||
|  |  | ||||||
|     const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; |     const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; | ||||||
| @@ -321,7 +321,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() | |||||||
|     // instantiate the FPGA switch and set the |     // instantiate the FPGA switch and set the | ||||||
|     // switch position to DMA. |     // switch position to DMA. | ||||||
|     std::shared_ptr<Fpga_Switch> switch_fpga; |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|     switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|     switch_fpga->set_switch_position(0);  // set switch position to DMA |     switch_fpga->set_switch_position(0);  // set switch position to DMA | ||||||
|  |  | ||||||
|     // create the correspondign acquisition block according to the desired tracking signal |     // create the correspondign acquisition block according to the desired tracking signal | ||||||
| @@ -397,7 +397,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() | |||||||
| void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init() | void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init() | ||||||
| { | { | ||||||
|     config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); |     config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); | ||||||
|     config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"); |     config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"); | ||||||
|     config->set_property("Acquisition.threshold", "0.00001"); |     config->set_property("Acquisition.threshold", "0.00001"); | ||||||
|     config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); |     config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); | ||||||
|     config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); |     config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ class GpsL1CaPcpsAcquisitionTestFpga : public ::testing::Test | |||||||
| { | { | ||||||
| public: | public: | ||||||
|     bool acquire_signal(); |     bool acquire_signal(); | ||||||
|     std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; |     std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; | ||||||
|     std::vector<Gnss_Synchro> gnss_synchro_vec; |     std::vector<Gnss_Synchro> gnss_synchro_vec; | ||||||
|  |  | ||||||
|     const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; |     const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; | ||||||
| @@ -320,7 +320,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() | |||||||
|     // instantiate the FPGA switch and set the |     // instantiate the FPGA switch and set the | ||||||
|     // switch position to DMA. |     // switch position to DMA. | ||||||
|     std::shared_ptr<Fpga_Switch> switch_fpga; |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|     switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|     switch_fpga->set_switch_position(0);  // set switch position to DMA |     switch_fpga->set_switch_position(0);  // set switch position to DMA | ||||||
|  |  | ||||||
|     // create the correspondign acquisition block according to the desired tracking signal |     // create the correspondign acquisition block according to the desired tracking signal | ||||||
| @@ -396,7 +396,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() | |||||||
| void GpsL1CaPcpsAcquisitionTestFpga::init() | void GpsL1CaPcpsAcquisitionTestFpga::init() | ||||||
| { | { | ||||||
|     config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); |     config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); | ||||||
|     config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_Fpga"); |     config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_FPGA"); | ||||||
|     config->set_property("Acquisition.threshold", "0.00001"); |     config->set_property("Acquisition.threshold", "0.00001"); | ||||||
|     config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); |     config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); | ||||||
|     config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); |     config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); | ||||||
|   | |||||||
| @@ -638,11 +638,11 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|     // instantiate the FPGA switch and set the |     // instantiate the FPGA switch and set the | ||||||
|     // switch position to DMA. |     // switch position to DMA. | ||||||
|     std::shared_ptr<Fpga_Switch> switch_fpga; |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|     switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|     switch_fpga->set_switch_position(0);  // set switch position to DMA |     switch_fpga->set_switch_position(0);  // set switch position to DMA | ||||||
|  |  | ||||||
|     // create the correspondign acquisition block according to the desired tracking signal |     // create the correspondign acquisition block according to the desired tracking signal | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'G'; |             tmp_gnss_synchro.System = 'G'; | ||||||
|             signal = "1C"; |             signal = "1C"; | ||||||
| @@ -654,7 +654,7 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|  |  | ||||||
|             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'E'; |             tmp_gnss_synchro.System = 'E'; | ||||||
|             signal = "1B"; |             signal = "1B"; | ||||||
| @@ -666,7 +666,7 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|  |  | ||||||
|             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'E'; |             tmp_gnss_synchro.System = 'E'; | ||||||
|             signal = "5X"; |             signal = "5X"; | ||||||
| @@ -678,7 +678,7 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|  |  | ||||||
|             args.freq_band = 1;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 1;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'G'; |             tmp_gnss_synchro.System = 'G'; | ||||||
|             signal = "L5"; |             signal = "L5"; | ||||||
| @@ -732,19 +732,19 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|  |  | ||||||
|     // number of samples that the DMA has to transfer |     // number of samples that the DMA has to transfer | ||||||
|     unsigned int nsamples_to_transfer; |     unsigned int nsamples_to_transfer; | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else  // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) |     else  // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
| @@ -762,7 +762,7 @@ bool HybridObservablesTestFpga::acquire_signal() | |||||||
|             acquisition->init(); |             acquisition->init(); | ||||||
|             acquisition->set_local_code(); |             acquisition->set_local_code(); | ||||||
|  |  | ||||||
|             if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) |             if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) | ||||||
|                 { |                 { | ||||||
|                     // Skip the first TEST_OBS_SKIP_SAMPLES samples |                     // Skip the first TEST_OBS_SKIP_SAMPLES samples | ||||||
|                     args.skip_used_samples = 0; |                     args.skip_used_samples = 0; | ||||||
| @@ -910,7 +910,7 @@ void HybridObservablesTestFpga::configure_receiver( | |||||||
|     config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); |     config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); | ||||||
|  |  | ||||||
|     std::string System_and_Signal; |     std::string System_and_Signal; | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro_master.System = 'G'; |             gnss_synchro_master.System = 'G'; | ||||||
|             std::string signal = "1C"; |             std::string signal = "1C"; | ||||||
| @@ -923,7 +923,7 @@ void HybridObservablesTestFpga::configure_receiver( | |||||||
|  |  | ||||||
|             config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); |             config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro_master.System = 'E'; |             gnss_synchro_master.System = 'E'; | ||||||
|             std::string signal = "1B"; |             std::string signal = "1B"; | ||||||
| @@ -939,7 +939,7 @@ void HybridObservablesTestFpga::configure_receiver( | |||||||
|  |  | ||||||
|             config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); |             config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga")  // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA")  // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) | ||||||
|         { |         { | ||||||
|             gnss_synchro_master.System = 'E'; |             gnss_synchro_master.System = 'E'; | ||||||
|             std::string signal = "5X"; |             std::string signal = "5X"; | ||||||
| @@ -953,7 +953,7 @@ void HybridObservablesTestFpga::configure_receiver( | |||||||
|  |  | ||||||
|             config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); |             config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro_master.System = 'G'; |             gnss_synchro_master.System = 'G'; | ||||||
|             std::string signal = "L5"; |             std::string signal = "L5"; | ||||||
| @@ -2031,22 +2031,22 @@ TEST_F(HybridObservablesTestFpga, ValidationOfResults) | |||||||
|     args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR; |     args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR; | ||||||
|  |  | ||||||
|     // reset the HW to clear the sample counters: the acquisition constructor generates a reset |     // reset the HW to clear the sample counters: the acquisition constructor generates a reset | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |             acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|             args.freq_band = 0; |             args.freq_band = 0; | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |             acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|             args.freq_band = 0; |             args.freq_band = 0; | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |             acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|             args.freq_band = 1; |             args.freq_band = 1; | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |             acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|             args.freq_band = 1; |             args.freq_band = 1; | ||||||
|   | |||||||
| @@ -355,7 +355,7 @@ void GpsL1CADllPllTrackingTestFpga::configure_receiver() | |||||||
|         std::to_string(baseband_sampling_freq)); |         std::to_string(baseband_sampling_freq)); | ||||||
|     // Set Tracking |     // Set Tracking | ||||||
|     config->set_property("Tracking_1C.implementation", |     config->set_property("Tracking_1C.implementation", | ||||||
|         "GPS_L1_CA_DLL_PLL_Tracking_Fpga"); |         "GPS_L1_CA_DLL_PLL_Tracking_FPGA"); | ||||||
|     config->set_property("Tracking_1C.item_type", "cshort"); |     config->set_property("Tracking_1C.item_type", "cshort"); | ||||||
|     config->set_property("Tracking_1C.dump", "true"); |     config->set_property("Tracking_1C.dump", "true"); | ||||||
|     config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); |     config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); | ||||||
|   | |||||||
| @@ -536,7 +536,7 @@ void TrackingPullInTestFpga::configure_receiver( | |||||||
|     config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); |     config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); | ||||||
|  |  | ||||||
|     std::string System_and_Signal; |     std::string System_and_Signal; | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro.System = 'G'; |             gnss_synchro.System = 'G'; | ||||||
|             std::string signal = "1C"; |             std::string signal = "1C"; | ||||||
| @@ -545,7 +545,7 @@ void TrackingPullInTestFpga::configure_receiver( | |||||||
|             config->set_property("Tracking.early_late_space_chips", "0.5"); |             config->set_property("Tracking.early_late_space_chips", "0.5"); | ||||||
|             config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); |             config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro.System = 'E'; |             gnss_synchro.System = 'E'; | ||||||
|             std::string signal = "1B"; |             std::string signal = "1B"; | ||||||
| @@ -557,7 +557,7 @@ void TrackingPullInTestFpga::configure_receiver( | |||||||
|             config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); |             config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); | ||||||
|             config->set_property("Tracking.track_pilot", "true"); |             config->set_property("Tracking.track_pilot", "true"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") | ||||||
|         { |         { | ||||||
|             gnss_synchro.System = 'E'; |             gnss_synchro.System = 'E'; | ||||||
|             std::string signal = "5X"; |             std::string signal = "5X"; | ||||||
| @@ -565,13 +565,13 @@ void TrackingPullInTestFpga::configure_receiver( | |||||||
|             signal.copy(gnss_synchro.Signal, 2, 0); |             signal.copy(gnss_synchro.Signal, 2, 0); | ||||||
|             if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b") |             if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b") | ||||||
|                 { |                 { | ||||||
|                     config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_Fpga")); |                     config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_FPGA")); | ||||||
|                 } |                 } | ||||||
|             config->set_property("Tracking.early_late_space_chips", "0.5"); |             config->set_property("Tracking.early_late_space_chips", "0.5"); | ||||||
|             config->set_property("Tracking.track_pilot", "true"); |             config->set_property("Tracking.track_pilot", "true"); | ||||||
|             config->set_property("Tracking.order", "2"); |             config->set_property("Tracking.order", "2"); | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             gnss_synchro.System = 'G'; |             gnss_synchro.System = 'G'; | ||||||
|             std::string signal = "L5"; |             std::string signal = "L5"; | ||||||
| @@ -634,11 +634,11 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|     // instantiate the FPGA switch and set the |     // instantiate the FPGA switch and set the | ||||||
|     // switch position to DMA. |     // switch position to DMA. | ||||||
|     std::shared_ptr<Fpga_Switch> switch_fpga; |     std::shared_ptr<Fpga_Switch> switch_fpga; | ||||||
|     switch_fpga = std::make_shared<Fpga_Switch>("/dev/uio1"); |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|     switch_fpga->set_switch_position(0);  // set switch position to DMA |     switch_fpga->set_switch_position(0);  // set switch position to DMA | ||||||
|  |  | ||||||
|     // create the correspondign acquisition block according to the desired tracking signal |     // create the correspondign acquisition block according to the desired tracking signal | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'G'; |             tmp_gnss_synchro.System = 'G'; | ||||||
|             signal = "1C"; |             signal = "1C"; | ||||||
| @@ -650,7 +650,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|  |  | ||||||
|             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'E'; |             tmp_gnss_synchro.System = 'E'; | ||||||
|             signal = "1B"; |             signal = "1B"; | ||||||
| @@ -662,7 +662,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|  |  | ||||||
|             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 0;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'E'; |             tmp_gnss_synchro.System = 'E'; | ||||||
|             signal = "5X"; |             signal = "5X"; | ||||||
| @@ -674,7 +674,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|  |  | ||||||
|             args.freq_band = 1;  // frequency band on which the DMA has to transfer the samples |             args.freq_band = 1;  // frequency band on which the DMA has to transfer the samples | ||||||
|         } |         } | ||||||
|     else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |     else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             tmp_gnss_synchro.System = 'G'; |             tmp_gnss_synchro.System = 'G'; | ||||||
|             signal = "L5"; |             signal = "L5"; | ||||||
| @@ -732,19 +732,19 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|  |  | ||||||
|     // number of samples that the DMA has to transfer |     // number of samples that the DMA has to transfer | ||||||
|     unsigned int nsamples_to_transfer; |     unsigned int nsamples_to_transfer; | ||||||
|     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |     if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |     else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |     else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
|     else  // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) |     else  // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) | ||||||
|         { |         { | ||||||
|             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); |             nsamples_to_transfer = static_cast<unsigned int>(std::round(static_cast<double>(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); | ||||||
|         } |         } | ||||||
| @@ -762,7 +762,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) | |||||||
|             acquisition->init(); |             acquisition->init(); | ||||||
|             acquisition->set_local_code(); |             acquisition->set_local_code(); | ||||||
|  |  | ||||||
|             if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) |             if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) | ||||||
|                 { |                 { | ||||||
|                     // Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal |                     // Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal | ||||||
|                     // states of the downsampling filter in the FPGA |                     // states of the downsampling filter in the FPGA | ||||||
| @@ -1079,22 +1079,22 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) | |||||||
|                             std::shared_ptr<AcquisitionInterface> acquisition; |                             std::shared_ptr<AcquisitionInterface> acquisition; | ||||||
|  |  | ||||||
|                             // reset the HW to clear the sample counters: the acquisition constructor generates a reset |                             // reset the HW to clear the sample counters: the acquisition constructor generates a reset | ||||||
|                             if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") |                             if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") | ||||||
|                                 { |                                 { | ||||||
|                                     acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |                                     acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|                                     args.freq_band = 0; |                                     args.freq_band = 0; | ||||||
|                                 } |                                 } | ||||||
|                             else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") |                             else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") | ||||||
|                                 { |                                 { | ||||||
|                                     acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |                                     acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|                                     args.freq_band = 0; |                                     args.freq_band = 0; | ||||||
|                                 } |                                 } | ||||||
|                             else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") |                             else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") | ||||||
|                                 { |                                 { | ||||||
|                                     acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |                                     acquisition = std::make_shared<GalileoE5aPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|                                     args.freq_band = 1; |                                     args.freq_band = 1; | ||||||
|                                 } |                                 } | ||||||
|                             else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") |                             else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") | ||||||
|                                 { |                                 { | ||||||
|                                     acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); |                                     acquisition = std::make_shared<GpsL5iPcpsAcquisitionFpga>(config.get(), "Acquisition", 0, 0); | ||||||
|                                     args.freq_band = 1; |                                     args.freq_band = 1; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez