diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc index 4138c038d..065838450 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -610,7 +610,7 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, cons // rx signal vectors std::vector input_samples(sample_block_size * 2); // complex samples // pointer to DMA buffer - std::array *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; @@ -631,8 +631,8 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, cons // 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_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; + dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; dma_index += 4; } } @@ -673,8 +673,8 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, cons 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_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; } @@ -704,8 +704,8 @@ void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, cons 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_buffer[dma_index] = input_samples[index0]; + dma_buffer[dma_index + 1] = input_samples[index0 + 1]; dma_index += 4; } } diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h index c2feb998d..f16f6f274 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h @@ -23,7 +23,11 @@ #include "concurrent_queue.h" #include "fpga_buffer_monitor.h" -#include "fpga_dma.h" +#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture +#include "fpga_dma-proxy.h" +#else +#include "fpga_ezdma.h" +#endif #include "fpga_dynamic_bit_selection.h" #include "fpga_switch.h" #include "gnss_block_interface.h" diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 2823283b7..64dfe3a60 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -19,8 +19,13 @@ if(ENABLE_FPGA OR ENABLE_AD9361) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) - set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma.h) + if(ARCH_64BITS) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h) + else() + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_ezdma.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_ezdma.h) + endif() endif() set(SIGNAL_SOURCE_LIB_SOURCES diff --git a/src/algorithms/signal_source/libs/fpga_dma.cc b/src/algorithms/signal_source/libs/fpga_dma-proxy.cc similarity index 56% rename from src/algorithms/signal_source/libs/fpga_dma.cc rename to src/algorithms/signal_source/libs/fpga_dma-proxy.cc index 286ef9324..1e8881300 100644 --- a/src/algorithms/signal_source/libs/fpga_dma.cc +++ b/src/algorithms/signal_source/libs/fpga_dma-proxy.cc @@ -1,5 +1,5 @@ /*! - * \file fpga_dma.cc + * \file fpga_dma-proxy.cc * \brief FPGA DMA control. This code is based in the Xilinx DMA proxy test application: * https://github.com/Xilinx-Wiki-Projects/software-prototypes/tree/master/linux-user-space-dma/Software * \author Marc Majoral, mmajoral(at)cttc.es @@ -15,7 +15,7 @@ * ----------------------------------------------------------------------------- */ -#include "fpga_dma.h" +#include "fpga_dma-proxy.h" #include #include // for std::cerr #include // for ioctl() @@ -24,7 +24,6 @@ int Fpga_DMA::DMA_open() { -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture tx_channel.fd = open("/dev/dma_proxy_tx", O_RDWR); if (tx_channel.fd < 1) { @@ -40,61 +39,29 @@ int Fpga_DMA::DMA_open() return -1; } -#else // 32-bit processor architecture - tx_fd = open("/dev/loop_tx", O_WRONLY); - if (tx_fd < 1) - { - return tx_fd; - } - // note: a problem was identified with the DMA: when switching from tx to rx or rx to tx mode - // the DMA transmission may hang. This problem will be fixed soon. - // for the moment this problem can be avoided by closing and opening the DMA a second time - if (close(tx_fd) < 0) - { - std::cerr << "Error closing loop device " << '\n'; - return -1; - } - // open the DMA a second time - tx_fd = open("/dev/loop_tx", O_WRONLY); - if (tx_fd < 1) - { - std::cerr << "Cannot open loop device\n"; - // stop the receiver - return tx_fd; - } -#endif - return 0; } - -std::array *Fpga_DMA::get_buffer_address() // NOLINT(readability-make-member-function-const) +int8_t *Fpga_DMA::get_buffer_address() // NOLINT(readability-make-member-function-const) { -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture - return &tx_channel.buf_ptr[0].buffer; -#else // 32-bit processor architecture - return &buffer; -#endif + return tx_channel.buf_ptr[0].buffer; } - int Fpga_DMA::DMA_write(int nbytes) const { -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture - int buffer_id = 0; tx_channel.buf_ptr[0].length = nbytes; // start DMA transfer - if (ioctl(tx_channel.fd, START_XFER, &buffer_id)) + if (ioctl(tx_channel.fd, _IOW('a', 'b', int32_t *), &buffer_id)) // start transfer { std::cerr << "Error starting tx DMA transfer " << '\n'; return -1; } // wait for completion of DMA transfer - if (ioctl(tx_channel.fd, FINISH_XFER, &buffer_id)) + if (ioctl(tx_channel.fd, _IOW('a', 'a', int32_t *), &buffer_id)) // finish transfer { std::cerr << "Error detecting end of DMA transfer " << '\n'; return -1; @@ -105,27 +72,16 @@ int Fpga_DMA::DMA_write(int nbytes) const std::cerr << "Proxy DMA Tx transfer error " << '\n'; return -1; } -#else // 32-bit processor architecture - const int num_bytes_sent = write(tx_fd, buffer.data(), nbytes); - if (num_bytes_sent != nbytes) - { - return -1; - } -#endif return 0; } int Fpga_DMA::DMA_close() const { -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture if (munmap(tx_channel.buf_ptr, sizeof(struct channel_buffer))) { std::cerr << "Failed to unmap DMA tx channel " << '\n'; return -1; } return close(tx_channel.fd); -#else // 32-bit processor architecture - return close(tx_fd); -#endif } diff --git a/src/algorithms/signal_source/libs/fpga_dma.h b/src/algorithms/signal_source/libs/fpga_dma-proxy.h similarity index 51% rename from src/algorithms/signal_source/libs/fpga_dma.h rename to src/algorithms/signal_source/libs/fpga_dma-proxy.h index 183500159..899b0177b 100644 --- a/src/algorithms/signal_source/libs/fpga_dma.h +++ b/src/algorithms/signal_source/libs/fpga_dma-proxy.h @@ -1,5 +1,5 @@ /*! - * \file fpga_dma.h + * \file fpga_dma-proxy.h * \brief FPGA DMA control. This code is based in the Xilinx DMA proxy test application: * https://github.com/Xilinx-Wiki-Projects/software-prototypes/tree/master/linux-user-space-dma/Software * \author Marc Majoral, mmajoral(at)cttc.es @@ -15,45 +15,11 @@ * ----------------------------------------------------------------------------- */ +#ifndef GNSS_SDR_FPGA_DMA_PROXY_H +#define GNSS_SDR_FPGA_DMA_PROXY_H -#ifndef GNSS_SDR_FPGA_DMA_H -#define GNSS_SDR_FPGA_DMA_H - -#include // for std::array #include // for std::int8_t -#define BUFFER_SIZE (128 * 1024) /* must match driver exactly */ - -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture - -#define TX_BUFFER_COUNT 1 /* app only, must be <= to the number in the driver */ - -#define FINISH_XFER _IOW('a', 'a', int32_t *) -#define START_XFER _IOW('a', 'b', int32_t *) - -// channel buffer structure -struct channel_buffer -{ - std::array buffer; - enum proxy_status - { - PROXY_NO_ERROR = 0, - PROXY_BUSY = 1, - PROXY_TIMEOUT = 2, - PROXY_ERROR = 3 - } status; - unsigned int length; -} __attribute__((aligned(1024))); /* 64 byte alignment required for DMA, but 1024 handy for viewing memory */ - -// internal DMA channel data structure -struct channel -{ - struct channel_buffer *buf_ptr; - int fd; -}; - -#endif - /*! * \brief Class that controls the switch DMA in the FPGA */ @@ -78,7 +44,7 @@ public: /*! * \brief Obtain DMA buffer address. */ - std::array *get_buffer_address(void); // NOLINT(readability-make-member-function-const) + int8_t *get_buffer_address(void); // NOLINT(readability-make-member-function-const) /*! * \brief Transfer DMA data @@ -91,11 +57,31 @@ public: int DMA_close(void) const; private: -#if INTPTR_MAX == INT64_MAX // 64-bit processor architecture + static const uint32_t DMA_MAX_BUFFER_SIZE = (128 * 1024); /* must match driver exactly */ + static const uint32_t TX_BUFFER_COUNT = 1; + + // channel buffer structure + struct channel_buffer + { + //std::array buffer; + int8_t buffer[DMA_MAX_BUFFER_SIZE]; + enum proxy_status + { + PROXY_NO_ERROR = 0, + PROXY_BUSY = 1, + PROXY_TIMEOUT = 2, + PROXY_ERROR = 3 + } status; + unsigned int length; + } __attribute__((aligned(1024))); /* 64 byte alignment required for DMA, but 1024 handy for viewing memory */ + + // internal DMA channel data structure + struct channel + { + struct channel_buffer *buf_ptr; + int fd; + }; + channel tx_channel; -#else // 32-bit processor architecture - std::array buffer; - int tx_fd; -#endif }; -#endif // GNSS_SDR_FPGA_DMA_H +#endif // GNSS_SDR_FPGA_DMA_PROXY_H diff --git a/src/algorithms/signal_source/libs/fpga_ezdma.cc b/src/algorithms/signal_source/libs/fpga_ezdma.cc new file mode 100644 index 000000000..cb8f5497e --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_ezdma.cc @@ -0,0 +1,68 @@ +/*! + * \file fpga_edma.cc + * \brief FPGA DMA control using the ezdma (See https://github.com/jeremytrimble/ezdma). + * \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-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ +#include "fpga_ezdma.h" +#include +#include // for std::cerr +#include + +int Fpga_DMA::DMA_open() +{ + tx_fd = open("/dev/loop_tx", O_WRONLY); + if (tx_fd < 1) + { + return tx_fd; + } + // note: a problem was identified with the DMA: when switching from tx to rx or rx to tx mode + // the DMA transmission may hang. This problem will be fixed soon. + // for the moment this problem can be avoided by closing and opening the DMA a second time + if (close(tx_fd) < 0) + { + std::cerr << "Error closing loop device " << '\n'; + return -1; + } + // open the DMA a second time + tx_fd = open("/dev/loop_tx", O_WRONLY); + if (tx_fd < 1) + { + std::cerr << "Cannot open loop device\n"; + // stop the receiver + return tx_fd; + } + return 0; +} + + +int8_t *Fpga_DMA::get_buffer_address() +{ + return buffer; +} + + +int Fpga_DMA::DMA_write(int nbytes) const +{ + const int num_bytes_sent = write(tx_fd, buffer, nbytes); + if (num_bytes_sent != nbytes) + { + return -1; + } + return 0; +} + + +int Fpga_DMA::DMA_close() const +{ + return close(tx_fd); +} diff --git a/src/algorithms/signal_source/libs/fpga_ezdma.h b/src/algorithms/signal_source/libs/fpga_ezdma.h new file mode 100644 index 000000000..801d2a6b7 --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_ezdma.h @@ -0,0 +1,64 @@ +/*! + * \file fpga_ezdma.h + * \brief FPGA DMA control using the ezdma (See https://github.com/jeremytrimble/ezdma). + * \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-2022 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_FPGA_EDMA_H +#define GNSS_SDR_FPGA_EDMA_H + +#include // for std::int8_t + +/*! + * \brief Class that controls the switch DMA in the FPGA + */ +class Fpga_DMA +{ +public: + /*! + * \brief Default constructor. + */ + Fpga_DMA() = default; + + /*! + * \brief Default destructor. + */ + ~Fpga_DMA() = default; + + /*! + * \brief Open the DMA device driver. + */ + int DMA_open(void); + + /*! + * \brief Obtain DMA buffer address. + */ + int8_t *get_buffer_address(void); // NOLINT(readability-make-member-function-const) + + /*! + * \brief Transfer DMA data + */ + int DMA_write(int nbytes) const; + + /*! + * \brief Close the DMA device driver + */ + int DMA_close(void) const; + +private: + static const uint32_t DMA_MAX_BUFFER_SIZE = 4 * 16384; // 4-channel 16384-sample buffers + int8_t buffer[DMA_MAX_BUFFER_SIZE]; + int tx_fd; +}; +#endif // GNSS_SDR_FPGA_EDMA_H