From 1d83a2b247f8e83bbce802a272ffa165bbc6333f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 8 Oct 2024 15:25:45 +0200 Subject: Get fixed_point working with USRP --- src/output/SDR.cpp | 1 + src/output/SDR.h | 4 ---- src/output/SDRDevice.h | 4 ++-- src/output/UHD.cpp | 23 ++++++++++------------- src/output/UHD.h | 3 --- 5 files changed, 13 insertions(+), 22 deletions(-) (limited to 'src/output') diff --git a/src/output/SDR.cpp b/src/output/SDR.cpp index 594171f..22398c7 100644 --- a/src/output/SDR.cpp +++ b/src/output/SDR.cpp @@ -34,6 +34,7 @@ #include "RemoteControl.h" #include "Utils.h" +#include #include #include #include diff --git a/src/output/SDR.h b/src/output/SDR.h index 960de0c..86bf295 100644 --- a/src/output/SDR.h +++ b/src/output/SDR.h @@ -34,16 +34,12 @@ DESCRIPTION: # include #endif -#include #include "ModPlugin.h" -#include "EtiReader.h" #include "output/SDRDevice.h" #include "output/Feedback.h" namespace Output { -using complexf = std::complex; - class SDR : public ModOutput, public ModMetadata, public RemoteControllable { public: SDR(SDRDeviceConfig& config, std::shared_ptr device); diff --git a/src/output/SDRDevice.h b/src/output/SDRDevice.h index 378829c..ec9373d 100644 --- a/src/output/SDRDevice.h +++ b/src/output/SDRDevice.h @@ -38,9 +38,7 @@ DESCRIPTION: #include #include #include -#include #include -#include #include "TimestampDecoder.h" @@ -59,6 +57,8 @@ struct SDRDeviceConfig { std::string tx_antenna; std::string rx_antenna; + bool fixedPoint = false; + long masterClockRate = 32768000; unsigned sampleRate = 2048000; double frequency = 0.0; diff --git a/src/output/UHD.cpp b/src/output/UHD.cpp index e097692..b30f9e1 100644 --- a/src/output/UHD.cpp +++ b/src/output/UHD.cpp @@ -31,10 +31,7 @@ //#define MDEBUG(fmt, args...) fprintf(LOG, fmt , ## args) #define MDEBUG(fmt, args...) -#include "PcDebug.h" #include "Log.h" -#include "RemoteControl.h" -#include "Utils.h" #include #include @@ -52,14 +49,12 @@ # include #endif - -#include #include -#include +#include +#include #include -#include +#include #include -#include #include #include @@ -235,7 +230,8 @@ UHD::UHD(SDRDeviceConfig& config) : m_usrp->set_rx_gain(m_conf.rxgain); etiLog.log(debug, "OutputUHD:Actual RX Gain: %f", m_usrp->get_rx_gain()); - const uhd::stream_args_t stream_args("fc32"); //complex floats + const uhd::stream_args_t stream_args( + m_conf.fixedPoint ? "sc16" : "fc32"); m_rx_stream = m_usrp->get_rx_stream(stream_args); m_tx_stream = m_usrp->get_tx_stream(stream_args); @@ -319,8 +315,9 @@ double UHD::get_bandwidth(void) const void UHD::transmit_frame(struct FrameData&& frame) { const double tx_timeout = 20.0; - const size_t sizeIn = frame.buf.size() / sizeof(complexf); - const complexf* in_data = reinterpret_cast(&frame.buf[0]); + + const size_t sample_size = m_conf.fixedPoint ? (2 * sizeof(int16_t)) : sizeof(complexf); + const size_t sizeIn = frame.buf.size() / sample_size; uhd::tx_metadata_t md_tx; @@ -353,9 +350,9 @@ void UHD::transmit_frame(struct FrameData&& frame) samps_to_send <= usrp_max_num_samps ); m_require_timestamp_refresh = false; - //send a single packet + // send a single packet size_t num_tx_samps = m_tx_stream->send( - &in_data[num_acc_samps], + frame.buf.data() + sample_size * num_acc_samps, samps_to_send, md_tx, tx_timeout); etiLog.log(trace, "UHD,sent %zu of %zu", num_tx_samps, samps_to_send); diff --git a/src/output/UHD.h b/src/output/UHD.h index 9891c7a..c4f1a45 100644 --- a/src/output/UHD.h +++ b/src/output/UHD.h @@ -45,12 +45,9 @@ DESCRIPTION: #include #include -#include "Log.h" #include "output/SDR.h" #include "output/USRPTime.h" #include "TimestampDecoder.h" -#include "RemoteControl.h" -#include "ThreadsafeQueue.h" #include #include -- cgit v1.2.3 From e836f903ae5e6b6916627142d47227a142879c04 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sat, 26 Oct 2024 16:30:19 +0200 Subject: Use FFT Accelerator on DEXTER --- src/DabModulator.cpp | 11 ++- src/OfdmGenerator.cpp | 206 +++++++++++++++++++++++++++++++++++++++++++++++--- src/OfdmGenerator.h | 48 +++++++++++- src/output/Dexter.h | 12 +-- 4 files changed, 258 insertions(+), 19 deletions(-) (limited to 'src/output') diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 9e9d017..757b01f 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -190,7 +190,16 @@ int DabModulator::process(Buffer* dataOut) shared_ptr cifOfdm; - if (m_settings.fixedPoint) { + if (m_settings.useDexterOutput) { + cifOfdm = make_shared( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + } + else if (m_settings.fixedPoint) { cifOfdm = make_shared( (1 + m_nbSymbols), m_nbCarriers, diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index e679694..198c2fc 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2023 + Copyright (C) 2024 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -64,8 +64,7 @@ OfdmGeneratorCF32::OfdmGeneratorCF32(size_t nbSymbols, nbSymbols, nbCarriers, spacing, inverse ? "true" : "false", this); if (nbCarriers > spacing) { - throw std::runtime_error( - "OfdmGenerator::OfdmGenerator nbCarriers > spacing!"); + throw std::runtime_error("OfdmGenerator nbCarriers > spacing!"); } /* register the parameters that can be remote controlled */ @@ -162,8 +161,8 @@ int OfdmGeneratorCF32::process(Buffer* const dataIn, Buffer* dataOut) dataOut->setLength(myNbSymbols * mySpacing * sizeof(complexf)); - FFTW_TYPE* in = reinterpret_cast(dataIn->getData()); - FFTW_TYPE* out = reinterpret_cast(dataOut->getData()); + FFTW_TYPE *in = reinterpret_cast(dataIn->getData()); + FFTW_TYPE *out = reinterpret_cast(dataOut->getData()); size_t sizeIn = dataIn->getLength() / sizeof(complexf); size_t sizeOut = dataOut->getLength() / sizeof(complexf); @@ -205,7 +204,7 @@ int OfdmGeneratorCF32::process(Buffer* const dataIn, Buffer* dataOut) myPaprAfterCFR.clear(); } - for (size_t i = 0; i < myNbSymbols; ++i) { + for (size_t i = 0; i < myNbSymbols; i++) { myFftIn[0][0] = 0; myFftIn[0][1] = 0; @@ -485,8 +484,7 @@ OfdmGeneratorFixed::OfdmGeneratorFixed(size_t nbSymbols, etiLog.level(info) << "Using KISS FFT by Mark Borgerding for fixed-point transform"; if (nbCarriers > spacing) { - throw std::runtime_error( - "OfdmGenerator::OfdmGenerator nbCarriers > spacing!"); + throw std::runtime_error("OfdmGenerator nbCarriers > spacing!"); } if (inverse) { @@ -538,8 +536,8 @@ int OfdmGeneratorFixed::process(Buffer* const dataIn, Buffer* dataOut) { dataOut->setLength(myNbSymbols * mySpacing * sizeof(kiss_fft_cpx)); - kiss_fft_cpx* in = reinterpret_cast(dataIn->getData()); - kiss_fft_cpx* out = reinterpret_cast(dataOut->getData()); + kiss_fft_cpx *in = reinterpret_cast(dataIn->getData()); + kiss_fft_cpx *out = reinterpret_cast(dataOut->getData()); size_t sizeIn = dataIn->getLength() / sizeof(kiss_fft_cpx); size_t sizeOut = dataOut->getLength() / sizeof(kiss_fft_cpx); @@ -561,7 +559,7 @@ int OfdmGeneratorFixed::process(Buffer* const dataIn, Buffer* dataOut) "OfdmGenerator::process output size not valid!"); } - for (size_t i = 0; i < myNbSymbols; ++i) { + for (size_t i = 0; i < myNbSymbols; i++) { myFftIn[0].r = 0; myFftIn[0].i = 0; @@ -584,3 +582,189 @@ int OfdmGeneratorFixed::process(Buffer* const dataIn, Buffer* dataOut) return sizeOut; } + +#ifdef HAVE_DEXTER +OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, + size_t nbCarriers, + size_t spacing, + bool& enableCfr, + float& cfrClip, + float& cfrErrorClip, + bool inverse) : + ModCodec(), + myNbSymbols(nbSymbols), + myNbCarriers(nbCarriers), + mySpacing(spacing) +{ + PDEBUG("OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(%zu, %zu, %zu, %s) @ %p\n", + nbSymbols, nbCarriers, spacing, inverse ? "true" : "false", this); + + etiLog.level(info) << "Using DEXTER FFT Aceelerator for fixed-point transform"; + + if (nbCarriers > spacing) { + throw std::runtime_error("OfdmGenerator nbCarriers > spacing!"); + } + + if (inverse) { + myPosDst = (nbCarriers & 1 ? 0 : 1); + myPosSrc = 0; + myPosSize = (nbCarriers + 1) / 2; + myNegDst = spacing - (nbCarriers / 2); + myNegSrc = (nbCarriers + 1) / 2; + myNegSize = nbCarriers / 2; + } + else { + myPosDst = (nbCarriers & 1 ? 0 : 1); + myPosSrc = nbCarriers / 2; + myPosSize = (nbCarriers + 1) / 2; + myNegDst = spacing - (nbCarriers / 2); + myNegSrc = 0; + myNegSize = nbCarriers / 2; + } + myZeroDst = myPosDst + myPosSize; + myZeroSize = myNegDst - myZeroDst; + + PDEBUG(" myPosDst: %u\n", myPosDst); + PDEBUG(" myPosSrc: %u\n", myPosSrc); + PDEBUG(" myPosSize: %u\n", myPosSize); + PDEBUG(" myNegDst: %u\n", myNegDst); + PDEBUG(" myNegSrc: %u\n", myNegSrc); + PDEBUG(" myNegSize: %u\n", myNegSize); + PDEBUG(" myZeroDst: %u\n", myZeroDst); + PDEBUG(" myZeroSize: %u\n", myZeroSize); + + const int N = mySpacing; // The size of the FFT + const size_t nbytes = N * sizeof(complexfix); + +#define IIO_ENSURE(expr, err) { \ + if (!(expr)) { \ + etiLog.log(error, "%s (%s:%d)\n", err, __FILE__, __LINE__); \ + throw std::runtime_error("Failed to set FFT for OfdmGeneratorDEXTER"); \ + } \ +} + IIO_ENSURE((m_ctx = iio_create_default_context()), "No context"); + IIO_ENSURE(m_dev_in = iio_context_find_device(m_ctx, "fft-accelerator-in"), "no dev"); + IIO_ENSURE(m_dev_out = iio_context_find_device(m_ctx, "fft-accelerator-out"), "no dev"); + IIO_ENSURE(m_channel_in = iio_device_find_channel(m_dev_in, "voltage0", true), "no channel"); + IIO_ENSURE(m_channel_out = iio_device_find_channel(m_dev_out, "voltage0", false), "no channel"); + + iio_channel_enable(m_channel_in); + iio_channel_enable(m_channel_out); + + m_buf_in = iio_device_create_buffer(m_dev_in, nbytes, false); + if (!m_buf_in) { + throw std::runtime_error("OfdmGeneratorDEXTER could not create in buffer"); + } + + m_buf_out = iio_device_create_buffer(m_dev_out, nbytes, false); + if (!m_buf_out) { + throw std::runtime_error("OfdmGeneratorDEXTER could not create out buffer"); + } +} + +OfdmGeneratorDEXTER::~OfdmGeneratorDEXTER() +{ + if (m_buf_in) { + iio_buffer_destroy(m_buf_in); + m_buf_in = nullptr; + } + + if (m_buf_out) { + iio_buffer_destroy(m_buf_out); + m_buf_out = nullptr; + } + + if (m_channel_in) { + iio_channel_disable(m_channel_in); + m_channel_in = nullptr; + } + + if (m_channel_out) { + iio_channel_disable(m_channel_out); + m_channel_out = nullptr; + } + + if (m_ctx) { + iio_context_destroy(m_ctx); + m_ctx = nullptr; + } +} + +int OfdmGeneratorDEXTER::process(Buffer* const dataIn, Buffer* dataOut) +{ + dataOut->setLength(myNbSymbols * mySpacing * sizeof(complexfix)); + + complexfix *in = reinterpret_cast(dataIn->getData()); + complexfix *out = reinterpret_cast(dataOut->getData()); + + size_t sizeIn = dataIn->getLength() / sizeof(complexfix); + size_t sizeOut = dataOut->getLength() / sizeof(complexfix); + + if (sizeIn != myNbSymbols * myNbCarriers) { + PDEBUG("Nb symbols: %zu\n", myNbSymbols); + PDEBUG("Nb carriers: %zu\n", myNbCarriers); + PDEBUG("Spacing: %zu\n", mySpacing); + PDEBUG("\n%zu != %zu\n", sizeIn, myNbSymbols * myNbCarriers); + throw std::runtime_error( + "OfdmGenerator::process input size not valid!"); + } + if (sizeOut != myNbSymbols * mySpacing) { + PDEBUG("Nb symbols: %zu\n", myNbSymbols); + PDEBUG("Nb carriers: %zu\n", myNbCarriers); + PDEBUG("Spacing: %zu\n", mySpacing); + PDEBUG("\n%zu != %zu\n", sizeIn, myNbSymbols * mySpacing); + throw std::runtime_error("OfdmGenerator::process output size not valid!"); + } + + ptrdiff_t iio_buf_size = (uint8_t*)iio_buffer_end(m_buf_in) - (uint8_t*)iio_buffer_start(m_buf_in); + if (iio_buf_size != (ssize_t)(mySpacing * sizeof(complexfix))) { + throw std::runtime_error("OfdmGenerator::process incorrect iio buffer size!"); + } + + ptrdiff_t p_inc = iio_buffer_step(m_buf_out); + if (p_inc != 1) { + throw std::runtime_error("OfdmGenerator::process Wrong p_inc"); + } + + const uint8_t *fft_out = (const uint8_t*)iio_buffer_first(m_buf_out, m_channel_out); + const uint8_t *fft_out_end = (const uint8_t*)iio_buffer_end(m_buf_out); + if (((fft_out_end - fft_out) != (ssize_t)(mySpacing * sizeof(complexfix))) != 0) { + throw std::runtime_error("OfdmGenerator::process fft_out length invalid!"); + } + + complexfix *fft_in = reinterpret_cast(iio_buffer_start(m_buf_in)); + + fft_in[0] = static_cast(0); + for (size_t i = 0; i < myZeroSize; i++) { + fft_in[myZeroDst + i] = static_cast(0); + } + + for (size_t i = 0; i < myNbSymbols; i++) { + /* For TM I this is: + * ZeroDst=769 ZeroSize=511 + * PosSrc=0 PosDst=1 PosSize=768 + * NegSrc=768 NegDst=1280 NegSize=768 + */ + memcpy(&fft_in[myPosDst], &in[myPosSrc], myPosSize * sizeof(complexfix)); + memcpy(&fft_in[myNegDst], &in[myNegSrc], myNegSize * sizeof(complexfix)); + + ssize_t nbytes_tx = iio_buffer_push(m_buf_in); + if (nbytes_tx < 0) { + throw std::runtime_error("OfdmGenerator::process error pushing IIO buffer!"); + } + + ssize_t nbytes_rx = iio_buffer_refill(m_buf_out); + if (nbytes_rx < 0) { + throw std::runtime_error("OfdmGenerator::process error refilling IIO buffer!"); + } + + memcpy(out, fft_out, mySpacing * sizeof(kiss_fft_cpx)); + + in += myNbCarriers; + out += mySpacing; + } + + return sizeOut; +} + +#endif // HAVE_DEXTER diff --git a/src/OfdmGenerator.h b/src/OfdmGenerator.h index 2e1aa63..b8ec702 100644 --- a/src/OfdmGenerator.h +++ b/src/OfdmGenerator.h @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2023 + Copyright (C) 2024 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -140,3 +140,49 @@ class OfdmGeneratorFixed : public ModCodec unsigned myZeroDst; unsigned myZeroSize; }; + +#ifdef HAVE_DEXTER +#include "iio.h" +// The PrecisionWave DEXTER device contains an FFT accelerator in FPGA +class OfdmGeneratorDEXTER : public ModCodec +{ + public: + OfdmGeneratorDEXTER(size_t nbSymbols, + size_t nbCarriers, + size_t spacing, + bool& enableCfr, + float& cfrClip, + float& cfrErrorClip, + bool inverse = true); + virtual ~OfdmGeneratorDEXTER(); + OfdmGeneratorDEXTER(const OfdmGeneratorDEXTER&) = delete; + OfdmGeneratorDEXTER& operator=(const OfdmGeneratorDEXTER&) = delete; + + int process(Buffer* const dataIn, Buffer* dataOut) override; + const char* name() override { return "OfdmGenerator"; } + + private: + struct iio_context *m_ctx = nullptr; + + // "in" and "out" are from the point of view of the FFT Accelerator block + struct iio_device *m_dev_in = nullptr; + struct iio_channel *m_channel_in = nullptr; + struct iio_buffer *m_buf_in = nullptr; + + struct iio_device *m_dev_out = nullptr; + struct iio_channel *m_channel_out = nullptr; + struct iio_buffer *m_buf_out = nullptr; + + const size_t myNbSymbols; + const size_t myNbCarriers; + const size_t mySpacing; + unsigned myPosSrc; + unsigned myPosDst; + unsigned myPosSize; + unsigned myNegSrc; + unsigned myNegDst; + unsigned myNegSize; + unsigned myZeroDst; + unsigned myZeroSize; +}; +#endif // HAVE_DEXTER diff --git a/src/output/Dexter.h b/src/output/Dexter.h index d4f425f..f8a17ba 100644 --- a/src/output/Dexter.h +++ b/src/output/Dexter.h @@ -98,16 +98,16 @@ class Dexter : public Output::SDRDevice SDRDeviceConfig& m_conf; - struct iio_context* m_ctx = nullptr; - struct iio_device* m_dexter_dsp_tx = nullptr; + struct iio_context *m_ctx = nullptr; + struct iio_device *m_dexter_dsp_tx = nullptr; - struct iio_device* m_ad9957 = nullptr; - struct iio_device* m_ad9957_tx0 = nullptr; - struct iio_channel* m_tx_channel = nullptr; + struct iio_device *m_ad9957 = nullptr; + struct iio_device *m_ad9957_tx0 = nullptr; + struct iio_channel *m_tx_channel = nullptr; struct iio_buffer *m_buffer = nullptr; /* Underflows are counted in a separate thread */ - struct iio_context* m_underflow_ctx = nullptr; + struct iio_context *m_underflow_ctx = nullptr; std::atomic m_running = ATOMIC_VAR_INIT(false); std::thread m_underflow_read_thread; void underflow_read_process(); -- cgit v1.2.3