diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-11-12 16:20:54 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-11-12 16:20:54 +0100 |
commit | 9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb (patch) | |
tree | df65604793d99946c0b83df82c110f37f0f369c7 | |
parent | b6a6cfc5636713e3f7b79d3ac12c9a2b31661549 (diff) | |
download | dabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.tar.gz dabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.tar.bz2 dabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.zip |
Replace gpioset calls by C code
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | src/OfdmGenerator.cpp | 129 |
2 files changed, 114 insertions, 21 deletions
diff --git a/configure.ac b/configure.ac index 5c3de90..d0258bc 100644 --- a/configure.ac +++ b/configure.ac @@ -113,13 +113,17 @@ AS_IF([test "x$enable_dexter" = "xyes"], [AC_CHECK_LIB([iio], [iio_create_scan_context], [IIO_LIBS="-liio"], [AC_MSG_ERROR([libiio is required])])]) +AS_IF([test "x$enable_dexter" = "xyes"], + [AC_CHECK_LIB([gpiod], [gpiod_chip_open], [GPIOD_LIBS="-lgpiod"], + [AC_MSG_ERROR([libgpiod is required])])]) + AS_IF([test "x$enable_bladerf" = "xyes"], [AC_CHECK_LIB([bladeRF], [bladerf_open], [BLADERF_LIBS="-lbladeRF"], [AC_MSG_ERROR([BladeRF library is required])])]) AC_SUBST([CFLAGS], ["$CFLAGS $EXTRA $FFTW_CFLAGS $SOAPYSDR_CFLAGS $PTHREAD_CFLAGS"]) AC_SUBST([CXXFLAGS], ["$CXXFLAGS $EXTRA $FFTW_CFLAGS $SOAPYSDR_CFLAGS $PTHREAD_CFLAGS"]) -AC_SUBST([LIBS], ["$FFTW_LIBS $SOAPYSDR_LIBS $PTHREAD_LIBS $ZMQ_LIBS $LIMESDR_LIBS $IIO_LIBS $BLADERF_LIBS"]) +AC_SUBST([LIBS], ["$FFTW_LIBS $SOAPYSDR_LIBS $PTHREAD_LIBS $ZMQ_LIBS $LIMESDR_LIBS $GPIOD_LIBS $IIO_LIBS $BLADERF_LIBS"]) # Checks for UHD. AS_IF([test "x$enable_output_uhd" = "xyes"], diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index d6698c2..16eb8d9 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -582,6 +582,114 @@ int OfdmGeneratorFixed::process(Buffer* const dataIn, Buffer* dataOut) } #ifdef HAVE_DEXTER +#include <gpiod.h> + +#define CHIP_PATH "/dev/gpiochip0" +#define LINE_FWD_INV 0 +#define LINE_CONFIG_TDATA_VALID 31 + +// GPIO mapping on write: +// bit 31 config_tdata_tvalid +// bit 30 resets the latches in the xfft_wrapper +// bits 15..0 are 1:1 xfft `config_tdata` +// `GPIO[0] = FWD_INV` according to Vivado + +static struct gpiod_line_request * +request_output_lines(const char *chip_path, const unsigned int *offsets, + enum gpiod_line_value *values, unsigned int num_lines, + const char *consumer) +{ + struct gpiod_request_config *rconfig = NULL; + struct gpiod_line_request *request = NULL; + struct gpiod_line_settings *settings; + struct gpiod_line_config *lconfig; + struct gpiod_chip *chip; + unsigned int i; + int ret; + + chip = gpiod_chip_open(chip_path); + if (!chip) + return NULL; + + settings = gpiod_line_settings_new(); + if (!settings) + goto close_chip; + + gpiod_line_settings_set_direction(settings, + GPIOD_LINE_DIRECTION_OUTPUT); + + lconfig = gpiod_line_config_new(); + if (!lconfig) + goto free_settings; + + for (i = 0; i < num_lines; i++) { + ret = gpiod_line_config_add_line_settings(lconfig, &offsets[i], + 1, settings); + if (ret) + goto free_line_config; + } + gpiod_line_config_set_output_values(lconfig, values, num_lines); + + if (consumer) { + rconfig = gpiod_request_config_new(); + if (!rconfig) + goto free_line_config; + + gpiod_request_config_set_consumer(rconfig, consumer); + } + + request = gpiod_chip_request_lines(chip, rconfig, lconfig); + + gpiod_request_config_free(rconfig); + +free_line_config: + gpiod_line_config_free(lconfig); + +free_settings: + gpiod_line_settings_free(settings); + +close_chip: + gpiod_chip_close(chip); + + return request; +} + +// The GPIO is connected to the config AXI bus of the xfft block. +// 15..0 is the config data; 31 is tvalid +void set_fft_accelerator_config(bool inverse) +{ + constexpr size_t NUM_LINES = 2; + unsigned int line_offsets[NUM_LINES]; + enum gpiod_line_value values[NUM_LINES]; + + line_offsets[0] = LINE_CONFIG_TDATA_VALID; + values[0] = GPIOD_LINE_VALUE_INACTIVE; + + line_offsets[1] = LINE_FWD_INV; + values[1] = inverse ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE; + + struct gpiod_line_request *request; + + request = request_output_lines(CHIP_PATH, line_offsets, values, NUM_LINES, "fft-config"); + if (!request) { + fprintf(stderr, "failed to request line: %s\n", strerror(errno)); + throw std::runtime_error("Request GPIO lines error"); + } + + usleep(100000); + + values[0] = GPIOD_LINE_VALUE_ACTIVE; + gpiod_line_request_set_values(request, values); + + usleep(100000); + + values[0] = GPIOD_LINE_VALUE_INACTIVE; + gpiod_line_request_set_values(request, values); + + gpiod_line_request_release(request); +} + + OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, size_t nbCarriers, size_t spacing, @@ -599,26 +707,7 @@ OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, etiLog.level(info) << "Using DEXTER FFT Accelerator for fixed-point transform"; - // I tried to get this to work in code using libgpiod, but life is too short to waste time on that. - // It works through gpioset, so we just call it - // The GPIO is connected to the config AXI bus of the xfft block. - // 15..0 is the config data; 31 is tvalid - if (inverse) { - if (system("gpioset gpiochip0 0=0 31=0") != 0) - throw std::runtime_error("Failed to call gpioset #1"); - if (system("gpioset gpiochip0 0=0 31=1") != 0) - throw std::runtime_error("Failed to call gpioset #2"); - if (system("gpioset gpiochip0 0=0 31=0") != 0) - throw std::runtime_error("Failed to call gpioset #3"); - } - else { - if (system("gpioset gpiochip0 0=1 31=0") != 0) - throw std::runtime_error("Failed to call gpioset #1"); - if (system("gpioset gpiochip0 0=1 31=1") != 0) - throw std::runtime_error("Failed to call gpioset #2"); - if (system("gpioset gpiochip0 0=1 31=0") != 0) - throw std::runtime_error("Failed to call gpioset #3"); - } + set_fft_accelerator_config(inverse); if (nbCarriers > spacing) { throw std::runtime_error("OfdmGenerator nbCarriers > spacing!"); |