mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-31 07:13:03 +00:00 
			
		
		
		
	Decouple the FPGA DMA signal source from the AD9361 FPGA signal source.
This commit is contained in:
		| @@ -41,6 +41,14 @@ if(ENABLE_AD9361) | |||||||
|     list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h) |     list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_FPGA) | ||||||
|  |     ############################################### | ||||||
|  |     # FPGA DMA source | ||||||
|  |     ############################################### | ||||||
|  |     list(APPEND OPT_DRIVER_SOURCES dma_fpga_signal_source.cc) | ||||||
|  |     list(APPEND OPT_DRIVER_HEADERS dma_fpga_signal_source.h) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) | if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) | ||||||
|     list(APPEND OPT_DRIVER_SOURCES flexiband_signal_source.cc) |     list(APPEND OPT_DRIVER_SOURCES flexiband_signal_source.cc) | ||||||
|     list(APPEND OPT_DRIVER_HEADERS flexiband_signal_source.h) |     list(APPEND OPT_DRIVER_HEADERS flexiband_signal_source.h) | ||||||
|   | |||||||
| @@ -26,22 +26,14 @@ | |||||||
| #include "GPS_L1_CA.h" | #include "GPS_L1_CA.h" | ||||||
| #include "GPS_L5.h" | #include "GPS_L5.h" | ||||||
| #include "ad9361_manager.h" | #include "ad9361_manager.h" | ||||||
| #include "command_event.h" |  | ||||||
| #include "configuration_interface.h" | #include "configuration_interface.h" | ||||||
| #include "gnss_sdr_flags.h" | #include "gnss_sdr_flags.h" | ||||||
| #include "gnss_sdr_string_literals.h" | #include "gnss_sdr_string_literals.h" | ||||||
| #include "uio_fpga.h" |  | ||||||
| #include <iio.h> |  | ||||||
| #include <algorithm>  // for std::max | #include <algorithm>  // for std::max | ||||||
| #include <chrono>     // for std::chrono | #include <chrono>     // for std::chrono | ||||||
| #include <cmath>      // for std::floor | #include <cmath>      // for std::floor | ||||||
| #include <exception>  // for std::exception | #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 <iostream>   // for std::cout | ||||||
| #include <unistd.h>   // for write |  | ||||||
| #include <vector>     // fr std::vector |  | ||||||
|  |  | ||||||
| #if USE_GLOG_AND_GFLAGS | #if USE_GLOG_AND_GFLAGS | ||||||
| #include <glog/logging.h> | #include <glog/logging.h> | ||||||
| @@ -56,12 +48,10 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
|     const std::string &role, unsigned int in_stream, unsigned int out_stream, |     const std::string &role, unsigned int in_stream, unsigned int out_stream, | ||||||
|     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) |     Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused))) | ||||||
|     : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), |     : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), | ||||||
|       queue_(queue), |  | ||||||
|       gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), |       gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), | ||||||
|       gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", 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)), |       rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), | ||||||
|       filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), |       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_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), | ||||||
|       rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), |       rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), | ||||||
|       scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), |       scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), | ||||||
| @@ -71,18 +61,13 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
|       freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))), |       freq1_(configuration->property(role + ".freq1", static_cast<uint64_t>(GPS_L5_FREQ_HZ))), | ||||||
|       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), |       sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), | ||||||
|       bandwidth_(configuration->property(role + ".bandwidth", 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_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_))), |       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))), |       tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast<uint64_t>(500000))), | ||||||
|       Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))), |       Fpass_(configuration->property(role + ".Fpass", static_cast<float>(0.0))), | ||||||
|       Fstop_(configuration->property(role + ".Fstop", 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), |       in_stream_(in_stream), | ||||||
|       out_stream_(out_stream), |       out_stream_(out_stream), | ||||||
|       switch_position_(configuration->property(role + ".switch_position", 0)), |  | ||||||
|       item_size_(sizeof(int8_t)), |       item_size_(sizeof(int8_t)), | ||||||
|       enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), |       enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), | ||||||
|       filter_auto_(configuration->property(role + ".filter_auto", false)), |       filter_auto_(configuration->property(role + ".filter_auto", false)), | ||||||
| @@ -91,20 +76,15 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
|       bb_dc_(configuration->property(role + ".bb_dc", true)), |       bb_dc_(configuration->property(role + ".bb_dc", true)), | ||||||
|       rx1_enable_(configuration->property(role + ".rx1_enable", true)), |       rx1_enable_(configuration->property(role + ".rx1_enable", true)), | ||||||
|       rx2_enable_(configuration->property(role + ".rx2_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_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), | ||||||
|       enable_ovf_check_buffer_monitor_active_(false), |       enable_ovf_check_buffer_monitor_active_(true), | ||||||
|       dump_(configuration->property(role + ".dump", false)), |       dump_(configuration->property(role + ".dump", false)), | ||||||
| #if USE_GLOG_AND_GFLAGS | #if USE_GLOG_AND_GFLAGS | ||||||
|       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)), |       rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) | ||||||
| #else | #else | ||||||
|       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))), |       rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) | ||||||
| #endif | #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) || |     const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || | ||||||
|                                (configuration->property("Channels_1B.count", 0) > 0)); |                                (configuration->property("Channels_1B.count", 0) > 0)); | ||||||
|     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || |     const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || | ||||||
| @@ -126,169 +106,12 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
|         { |         { | ||||||
|             filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); |             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) |     switch_fpga = std::make_shared<Fpga_Switch>(); | ||||||
|         { |     switch_fpga->set_switch_position(switch_to_real_time_mode); | ||||||
|             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"; |     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 |     // 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")) |     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")) | ||||||
|         { |         { | ||||||
| @@ -429,24 +252,11 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
|                 } |                 } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|             // 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); |     std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); | ||||||
|  |  | ||||||
|             // find the uio device file corresponding to the buffer monitor |     buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(num_freq_bands, dump_, dump_filename); | ||||||
|             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(); }); |     thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); | ||||||
|         } |  | ||||||
|  |  | ||||||
|     // dynamic bits selection |     // dynamic bits selection | ||||||
|     if (enable_dynamic_bit_selection_) |     if (enable_dynamic_bit_selection_) | ||||||
| @@ -469,19 +279,7 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *con | |||||||
| Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() | Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() | ||||||
| { | { | ||||||
|     /* cleanup and exit */ |     /* 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_) |     if (rf_shutdown_) | ||||||
|         { |         { | ||||||
|             std::cout << "* AD9361 Disabling RX streaming channels\n"; |             std::cout << "* AD9361 Disabling RX streaming channels\n"; | ||||||
| @@ -503,19 +301,18 @@ Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() | |||||||
|         } |         } | ||||||
|  |  | ||||||
|     // disable buffer overflow checking and buffer monitoring |     // disable buffer overflow checking and buffer monitoring | ||||||
|             std::unique_lock<std::mutex> lock(buffer_monitor_mutex); |     std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex); | ||||||
|     enable_ovf_check_buffer_monitor_active_ = false; |     enable_ovf_check_buffer_monitor_active_ = false; | ||||||
|             lock.unlock(); |     lock_buffer_monitor.unlock(); | ||||||
|  |  | ||||||
|     if (thread_buffer_monitor.joinable()) |     if (thread_buffer_monitor.joinable()) | ||||||
|         { |         { | ||||||
|             thread_buffer_monitor.join(); |             thread_buffer_monitor.join(); | ||||||
|         } |         } | ||||||
|         } |  | ||||||
|  |  | ||||||
|     std::unique_lock<std::mutex> lock(dynamic_bit_selection_mutex); |     std::unique_lock<std::mutex> lock_dyn_bit_sel(dynamic_bit_selection_mutex); | ||||||
|     bool bit_selection_enabled = enable_dynamic_bit_selection_; |     bool bit_selection_enabled = enable_dynamic_bit_selection_; | ||||||
|     lock.unlock(); |     lock_dyn_bit_sel.unlock(); | ||||||
|  |  | ||||||
|     if (bit_selection_enabled == true) |     if (bit_selection_enabled == true) | ||||||
|         { |         { | ||||||
| @@ -531,290 +328,6 @@ Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| 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() | void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process() | ||||||
| { | { | ||||||
|     bool dynamic_bit_selection_active = true; |     bool dynamic_bit_selection_active = true; | ||||||
|   | |||||||
| @@ -53,8 +53,6 @@ public: | |||||||
|  |  | ||||||
|     ~Ad9361FpgaSignalSource(); |     ~Ad9361FpgaSignalSource(); | ||||||
|  |  | ||||||
|     void start() override; |  | ||||||
|  |  | ||||||
|     inline size_t item_size() override |     inline size_t item_size() override | ||||||
|     { |     { | ||||||
|         return item_size_; |         return item_size_; | ||||||
| @@ -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,12 +130,10 @@ 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_; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										585
									
								
								src/algorithms/signal_source/adapters/dma_fpga_signal_source.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										585
									
								
								src/algorithms/signal_source/adapters/dma_fpga_signal_source.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,585 @@ | |||||||
|  | /*! | ||||||
|  |  * \file dma_fpga_signal_source.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_fpga_signal_source.h" | ||||||
|  | #include "command_event.h" | ||||||
|  | #include "configuration_interface.h" | ||||||
|  | #include "gnss_sdr_flags.h" | ||||||
|  | #include "gnss_sdr_string_literals.h" | ||||||
|  | #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; | ||||||
|  |  | ||||||
|  | DMAFpgaSignalSource::DMAFpgaSignalSource(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_Fpga_Signal_Source"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 | ||||||
|  |         { | ||||||
|  |             /*! | ||||||
|  |                      * 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_; | ||||||
|  |     //        } | ||||||
|  |  | ||||||
|  |     // 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"; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DMAFpgaSignalSource::~DMAFpgaSignalSource() | ||||||
|  | { | ||||||
|  |     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 DMAFpgaSignalSource::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 DMAFpgaSignalSource::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 DMAFpgaSignalSource::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 DMAFpgaSignalSource::connect(gr::top_block_sptr top_block) | ||||||
|  | { | ||||||
|  |     if (top_block) | ||||||
|  |         { /* top_block is not null */ | ||||||
|  |         }; | ||||||
|  |     DLOG(INFO) << "AD9361 FPGA source nothing to connect"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DMAFpgaSignalSource::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 DMAFpgaSignalSource::get_left_block() | ||||||
|  | { | ||||||
|  |     LOG(WARNING) << "Trying to get signal source left block."; | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | gr::basic_block_sptr DMAFpgaSignalSource::get_right_block() | ||||||
|  | { | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
							
								
								
									
										118
									
								
								src/algorithms/signal_source/adapters/dma_fpga_signal_source.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/algorithms/signal_source/adapters/dma_fpga_signal_source.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | /*! | ||||||
|  |  * \file dma_fpga_signal_source.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_FPGA_SIGNAL_SOURCE_H | ||||||
|  | #define GNSS_SDR_DMA_FPGA_SIGNAL_SOURCE_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 DMAFpgaSignalSource : public SignalSourceBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     DMAFpgaSignalSource(const ConfigurationInterface *configuration, | ||||||
|  |         const std::string &role, unsigned int in_stream, | ||||||
|  |         unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue); | ||||||
|  |  | ||||||
|  |     ~DMAFpgaSignalSource(); | ||||||
|  |  | ||||||
|  |     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_FPGA_SIGNAL_SOURCE_H | ||||||
| @@ -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,16 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, | //Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, | ||||||
|  | //    uint32_t num_freq_bands, | ||||||
|  | //    bool dump, | ||||||
|  | //    std::string dump_filename) | ||||||
|  | //    : d_dump_filename(std::move(dump_filename)), | ||||||
|  | //      d_num_freq_bands(num_freq_bands), | ||||||
|  | //      d_max_buff_occ_freq_band_0(0), | ||||||
|  | //      d_max_buff_occ_freq_band_1(0), | ||||||
|  | //      d_dump(dump) | ||||||
|  | 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 +60,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 | ||||||
|   | |||||||
| @@ -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); |     explicit 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; | ||||||
|   | |||||||
| @@ -128,6 +128,7 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if ENABLE_FPGA | #if ENABLE_FPGA | ||||||
|  | #include "dma_fpga_signal_source.h" | ||||||
| #include "galileo_e1_dll_pll_veml_tracking_fpga.h" | #include "galileo_e1_dll_pll_veml_tracking_fpga.h" | ||||||
| #include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" | #include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" | ||||||
| #include "galileo_e5a_dll_pll_tracking_fpga.h" | #include "galileo_e5a_dll_pll_tracking_fpga.h" | ||||||
| @@ -811,7 +812,7 @@ 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 |             // The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver | ||||||
|             // in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver. |             // 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") |             else if (implementation == "Ad9361_Fpga_Signal_Source") | ||||||
| @@ -822,6 +823,15 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock( | |||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if ENABLE_FPGA | ||||||
|  |             else if (implementation == "DMA_Fpga_Signal_Source") | ||||||
|  |                 { | ||||||
|  |                     std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<DMAFpgaSignalSource>(configuration, role, in_streams, | ||||||
|  |                         out_streams, queue); | ||||||
|  |                     block = std::move(block_); | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if ZEROMQ_DRIVER | #if ZEROMQ_DRIVER | ||||||
|             else if (implementation == "ZMQ_Signal_Source") |             else if (implementation == "ZMQ_Signal_Source") | ||||||
|                 { |                 { | ||||||
|   | |||||||
| @@ -547,7 +547,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_Fpga_Signal_Source or DMA_Fpga_Signal_Source\n"; | ||||||
|                     return 1; |                     return 1; | ||||||
|                 } |                 } | ||||||
|             if (src->item_size() == 0) |             if (src->item_size() == 0) | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -638,7 +638,7 @@ 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 | ||||||
|   | |||||||
| @@ -634,7 +634,7 @@ 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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Marc Majoral
					Marc Majoral