aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2024-11-12 16:20:54 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2024-11-12 16:20:54 +0100
commit9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb (patch)
treedf65604793d99946c0b83df82c110f37f0f369c7
parentb6a6cfc5636713e3f7b79d3ac12c9a2b31661549 (diff)
downloaddabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.tar.gz
dabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.tar.bz2
dabmod-9c4683b718fb785ebf7fa5e3cca21af6bd9dc4bb.zip
Replace gpioset calls by C code
-rw-r--r--configure.ac6
-rw-r--r--src/OfdmGenerator.cpp129
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!");