summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/src/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/HW/BladeRF/src/helpers')
-rw-r--r--Radio/HW/BladeRF/src/helpers/configfile.c342
-rw-r--r--Radio/HW/BladeRF/src/helpers/configfile.h27
-rw-r--r--Radio/HW/BladeRF/src/helpers/file.c511
-rw-r--r--Radio/HW/BladeRF/src/helpers/file.h97
-rw-r--r--Radio/HW/BladeRF/src/helpers/have_cap.h43
-rw-r--r--Radio/HW/BladeRF/src/helpers/interleave.c182
-rw-r--r--Radio/HW/BladeRF/src/helpers/interleave.h44
-rw-r--r--Radio/HW/BladeRF/src/helpers/timeout.c52
-rw-r--r--Radio/HW/BladeRF/src/helpers/timeout.h40
-rw-r--r--Radio/HW/BladeRF/src/helpers/version.c177
-rw-r--r--Radio/HW/BladeRF/src/helpers/version.h142
-rw-r--r--Radio/HW/BladeRF/src/helpers/wallclock.c47
-rw-r--r--Radio/HW/BladeRF/src/helpers/wallclock.h29
13 files changed, 1733 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/src/helpers/configfile.c b/Radio/HW/BladeRF/src/helpers/configfile.c
new file mode 100644
index 0000000..bfa339c
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/configfile.c
@@ -0,0 +1,342 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013-2018 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <libbladeRF.h>
+
+#include "conversions.h"
+#include "helpers/file.h"
+#include "log.h"
+#include "parse.h"
+
+/******************************************************************************/
+/* Config file stuff */
+/******************************************************************************/
+
+const struct numeric_suffix freq_suffixes[] = { { "G", 1000 * 1000 * 1000 },
+ { "GHz", 1000 * 1000 * 1000 },
+ { "M", 1000 * 1000 },
+ { "MHz", 1000 * 1000 },
+ { "k", 1000 },
+ { "kHz", 1000 } };
+#define NUM_FREQ_SUFFIXES (sizeof(freq_suffixes) / sizeof(freq_suffixes[0]))
+#define MAX(a, b) (a > b ? a : b)
+#define MIN(a, b) (a < b ? a : b)
+
+static int apply_config_options(struct bladerf *dev, struct config_options opt)
+{
+ int status;
+ bladerf_frequency freq;
+ bladerf_bandwidth bw;
+ uint32_t val;
+ bool ok;
+ bladerf_gain_mode gain_mode;
+ const struct bladerf_range *rx_range = NULL;
+ const struct bladerf_range *tx_range = NULL;
+ bladerf_sampling sampling_mode;
+ bladerf_vctcxo_tamer_mode tamer_mode = BLADERF_VCTCXO_TAMER_INVALID;
+
+ struct bladerf_rational_rate rate, actual;
+
+ status = BLADERF_ERR_INVAL;
+
+ if (!strcasecmp(opt.key, "biastee_tx")) {
+ bool enable = false;
+
+ status = str2bool(opt.value, &enable);
+ if (status < 0) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_bias_tee(dev, BLADERF_CHANNEL_TX(0), enable);
+ if (status < 0) {
+ return status;
+ }
+ } else if (!strcasecmp(opt.key, "biastee_rx")) {
+ bool enable = false;
+
+ status = str2bool(opt.value, &enable);
+ if (status < 0) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_bias_tee(dev, BLADERF_CHANNEL_RX(0), enable);
+ if (status < 0) {
+ return status;
+ }
+ } else if (!strcasecmp(opt.key, "fpga")) {
+ status = bladerf_load_fpga(dev, opt.value);
+ if (status < 0) {
+ log_warning("Config line %d: could not load FPGA from `%s'\n",
+ opt.lineno, opt.value);
+ }
+ return status;
+ } else if (!strcasecmp(opt.key, "frequency")) {
+ status =
+ bladerf_get_frequency_range(dev, BLADERF_CHANNEL_RX(0), &rx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ status =
+ bladerf_get_frequency_range(dev, BLADERF_CHANNEL_TX(0), &tx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ freq = str2uint64_suffix(opt.value, MAX(rx_range->min, tx_range->min),
+ MIN(rx_range->max, tx_range->max),
+ freq_suffixes, NUM_FREQ_SUFFIXES, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_CHANNEL_RX(0), freq);
+ if (status < 0) {
+ return status;
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_CHANNEL_TX(0), freq);
+ } else if (!strcasecmp(opt.key, "samplerate")) {
+ status = bladerf_get_sample_rate_range(dev, BLADERF_CHANNEL_RX(0),
+ &rx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ status = bladerf_get_sample_rate_range(dev, BLADERF_CHANNEL_TX(0),
+ &tx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ freq = str2uint64_suffix(opt.value, MAX(rx_range->min, tx_range->min),
+ MIN(rx_range->max, tx_range->max),
+ freq_suffixes, NUM_FREQ_SUFFIXES, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ rate.integer = freq;
+ rate.num = 0;
+ rate.den = 1;
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_CHANNEL_RX(0),
+ &rate, &actual);
+ if (status < 0) {
+ return status;
+ }
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_CHANNEL_TX(0),
+ &rate, &actual);
+ } else if (!strcasecmp(opt.key, "bandwidth")) {
+ status =
+ bladerf_get_bandwidth_range(dev, BLADERF_CHANNEL_RX(0), &rx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ status =
+ bladerf_get_bandwidth_range(dev, BLADERF_CHANNEL_TX(0), &tx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ if (MIN(rx_range->max, tx_range->max) >= UINT32_MAX) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ bw = str2uint_suffix(
+ opt.value, (bladerf_bandwidth)MAX(rx_range->min, tx_range->min),
+ (bladerf_bandwidth)MIN(rx_range->max, tx_range->max), freq_suffixes,
+ NUM_FREQ_SUFFIXES, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_CHANNEL_RX(0), bw, NULL);
+ if (status < 0) {
+ return status;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_CHANNEL_TX(0), bw, NULL);
+ } else if (!strcasecmp(opt.key, "agc")) {
+ bool agcval = false;
+
+ status = str2bool(opt.value, &agcval);
+ if (status != 0) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ gain_mode = agcval ? BLADERF_GAIN_AUTOMATIC : BLADERF_GAIN_MANUAL;
+ status = bladerf_set_gain_mode(dev, BLADERF_CHANNEL_RX(0), gain_mode);
+ } else if (!strcasecmp(opt.key, "gpio")) {
+ val = str2uint(opt.key, 0, -1, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_config_gpio_write(dev, val);
+ } else if (!strcasecmp(opt.key, "sampling")) {
+ if (!strcasecmp(opt.value, "internal")) {
+ sampling_mode = BLADERF_SAMPLING_INTERNAL;
+ } else if (!strcasecmp(opt.value, "external")) {
+ sampling_mode = BLADERF_SAMPLING_EXTERNAL;
+ } else {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_sampling(dev, sampling_mode);
+ } else if (!strcasecmp(opt.key, "trimdac")) {
+ val = str2uint(opt.value, 0, -1, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_dac_write(dev, val);
+ } else if (!strcasecmp(opt.key, "vctcxo_tamer")) {
+ if (!strcasecmp(opt.value, "disabled") ||
+ !strcasecmp(opt.value, "off")) {
+ tamer_mode = BLADERF_VCTCXO_TAMER_DISABLED;
+ } else if (!strcasecmp(opt.value, "1PPS") ||
+ !strcasecmp(opt.value, "1 PPS")) {
+ tamer_mode = BLADERF_VCTCXO_TAMER_1_PPS;
+ } else if (!strcasecmp(opt.value, "10MHZ") ||
+ !strcasecmp(opt.value, "10 MHZ")) {
+ tamer_mode = BLADERF_VCTCXO_TAMER_10_MHZ;
+ } else if (!strcasecmp(opt.value, "10M")) {
+ tamer_mode = BLADERF_VCTCXO_TAMER_10_MHZ;
+ } else {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_vctcxo_tamer_mode(dev, tamer_mode);
+ } else if (!strcasecmp(opt.key, "clock_ref")) {
+ bool enable = false;
+
+ status = str2bool(opt.value, &enable);
+ if (status != 0) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_pll_enable(dev, enable);
+ } else if (!strcasecmp(opt.key, "refin_freq")) {
+ status = bladerf_get_pll_refclk_range(dev, &rx_range);
+ if (status < 0) {
+ return status;
+ }
+
+ freq = str2uint64_suffix(opt.value, rx_range->min, rx_range->max,
+ freq_suffixes, NUM_FREQ_SUFFIXES, &ok);
+ if (!ok) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_pll_refclk(dev, freq);
+ } else if (!strcasecmp(opt.key, "clock_sel")) {
+ bladerf_clock_select clock_sel = CLOCK_SELECT_ONBOARD;
+
+ if (!strcasecmp(opt.value, "onboard") ||
+ !strcasecmp(opt.value, "internal")) {
+ clock_sel = CLOCK_SELECT_ONBOARD;
+ } else if (!strcasecmp(opt.value, "external")) {
+ clock_sel = CLOCK_SELECT_EXTERNAL;
+ } else {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_clock_select(dev, clock_sel);
+ } else if (!strcasecmp(opt.key, "clock_out")) {
+ bool enable = false;
+
+ status = str2bool(opt.value, &enable);
+ if (status != 0) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = bladerf_set_clock_output(dev, enable);
+ } else {
+ log_warning("Invalid key `%s' on line %d\n", opt.key, opt.lineno);
+ }
+
+ if (status < 0)
+ log_warning("Error message for option (%s) on line %d:\n%s\n", opt.key,
+ opt.lineno, bladerf_strerror(status));
+
+ return status;
+}
+
+int config_load_options_file(struct bladerf *dev)
+{
+ char *filename = NULL;
+ int status = 0;
+
+ uint8_t *buf = NULL;
+ size_t buf_size;
+
+ int optc;
+ int j;
+ struct config_options *optv;
+
+ filename = file_find("bladeRF.conf");
+ if (!filename) {
+ filename = file_find("bladerf.conf");
+
+ /* A missing file that is optional is not an error */
+ if (!filename) {
+ return 0;
+ }
+ }
+
+ status = file_read_buffer(filename, &buf, &buf_size);
+ if (status < 0) {
+ goto out;
+ }
+
+ optc = str2options(dev, (const char *)buf, buf_size, &optv);
+ if (optc < 0) {
+ status = BLADERF_ERR_INVAL;
+ goto out_buf;
+ }
+
+ for (j = 0; j < optc; j++) {
+ status = apply_config_options(dev, optv[j]);
+ if (status < 0) {
+ log_warning("Invalid config option `%s' on line %d\n", optv[j].key,
+ optv[j].lineno);
+ /* Some config options will require the FPGA to be loaded, however
+ * this function is called during bladerf_open(). The solution is
+ * to treat BLADERF_ERR_NOT_INIT as a warning and continue. */
+ if (status == BLADERF_ERR_NOT_INIT) {
+ status = 0;
+ } else {
+ break;
+ }
+ }
+ }
+
+ free_opts(optv, optc);
+
+out_buf:
+ free(buf);
+out:
+ free(filename);
+ return status;
+}
diff --git a/Radio/HW/BladeRF/src/helpers/configfile.h b/Radio/HW/BladeRF/src/helpers/configfile.h
new file mode 100644
index 0000000..390a4cf
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/configfile.h
@@ -0,0 +1,27 @@
+/**
+ * @file configfile.h
+ *
+ * @brief Configuration file support for libbladeRF
+ *
+ * Copyright (C) 2013-2018 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef CONFIGFILE_H_
+#define CONFIGFILE_H_
+
+int config_load_options_file(struct bladerf *dev);
+
+#endif // CONFIGFILE_H_
diff --git a/Radio/HW/BladeRF/src/helpers/file.c b/Radio/HW/BladeRF/src/helpers/file.c
new file mode 100644
index 0000000..0977137
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/file.c
@@ -0,0 +1,511 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013-2014 Nuand LLC
+ * Copyright (C) 2013 Daniel Gröber <dxld ÄT darkboxed DOT org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <libbladeRF.h>
+
+#include "host_config.h"
+#include "minmax.h"
+#include "log.h"
+#include "rel_assert.h"
+
+#include "helpers/file.h"
+
+/* Paths to search for bladeRF files */
+struct search_path_entries {
+ bool prepend_home;
+ const char *path;
+};
+
+int file_write(FILE *f, uint8_t *buf, size_t len)
+{
+ size_t rv;
+
+ rv = fwrite(buf, 1, len, f);
+ if(rv < len) {
+ log_debug("File write failed: %s\n", strerror(errno));
+ return BLADERF_ERR_IO;
+ }
+
+ return 0;
+}
+
+int file_read(FILE *f, char *buf, size_t len)
+{
+ size_t rv;
+
+ rv = fread(buf, 1, len, f);
+ if(rv < len) {
+ if(feof(f))
+ log_debug("Unexpected end of file: %s\n", strerror(errno));
+ else
+ log_debug("Error reading file: %s\n", strerror(errno));
+
+ return BLADERF_ERR_IO;
+ }
+
+ return 0;
+}
+
+ssize_t file_size(FILE *f)
+{
+ ssize_t rv = BLADERF_ERR_IO;
+ long int fpos = ftell(f);
+ long len;
+
+ if(fpos < 0) {
+ log_verbose("ftell failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ if(fseek(f, 0, SEEK_END)) {
+ log_verbose("fseek failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ len = ftell(f);
+ if(len < 0) {
+ log_verbose("ftell failed: %s\n", strerror(errno));
+ goto out;
+ } else if (len == LONG_MAX) {
+ log_debug("ftell called with a directory?\n");
+ goto out;
+ }
+
+ if(fseek(f, fpos, SEEK_SET)) {
+ log_debug("fseek failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ rv = (ssize_t) len;
+ assert(rv == len);
+
+out:
+ return rv;
+}
+
+int file_read_buffer(const char *filename, uint8_t **buf_ret, size_t *size_ret)
+{
+ int status = BLADERF_ERR_UNEXPECTED;
+ FILE *f;
+ uint8_t *buf = NULL;
+ ssize_t len;
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ log_error("%s: could not open %s: %s\n", __FUNCTION__, filename,
+ strerror(errno));
+ switch (errno) {
+ case ENOENT:
+ return BLADERF_ERR_NO_FILE;
+
+ case EACCES:
+ return BLADERF_ERR_PERMISSION;
+
+ default:
+ return BLADERF_ERR_IO;
+ }
+ }
+
+ len = file_size(f);
+ if (len < 0) {
+ status = BLADERF_ERR_IO;
+ goto out;
+ }
+
+ buf = (uint8_t *)malloc(len);
+ if (!buf) {
+ status = BLADERF_ERR_MEM;
+ goto out;
+ }
+
+ status = file_read(f, (char *)buf, len);
+ if (status < 0) {
+ goto out;
+ }
+
+ *buf_ret = buf;
+ *size_ret = len;
+ fclose(f);
+ return 0;
+
+out:
+ free(buf);
+ if (f) {
+ fclose(f);
+ }
+
+ return status;
+}
+
+/* Remove the last entry in a path. This is used to strip the executable name
+* from a path to get the directory that the executable resides in. */
+static size_t strip_last_path_entry(char *buf, char dir_delim)
+{
+ size_t len = strlen(buf);
+
+ while (len > 0 && buf[len - 1] != dir_delim) {
+ buf[len - 1] = '\0';
+ len--;
+ }
+
+ return len;
+}
+
+#if BLADERF_OS_LINUX || BLADERF_OS_OSX || BLADERF_OS_FREEBSD
+#define ACCESS_FILE_EXISTS F_OK
+#define DIR_DELIMETER '/'
+
+static const struct search_path_entries search_paths[] = {
+ { false, "" },
+ { true, "/.config/Nuand/bladeRF/" },
+ { true, "/.Nuand/bladeRF/" },
+
+ /* LIBBLADERF_SEARCH_PATH_PREFIX is defined in the libbladeRF
+ * CMakeLists.txt file. It defaults to ${CMAKE_INSTALL_PREFIX}, but
+ * can be overridden via -DLIBBLADERF_SEARCH_PATH_OVERRIDE
+ */
+ //{ false, LIBBLADERF_SEARCH_PREFIX "/etc/Nuand/bladeRF/" },
+ //{ false, LIBBLADERF_SEARCH_PREFIX "/share/Nuand/bladeRF/" },
+
+ /* These two entries are here for reverse compatibility.
+ *
+ * We failed to prefix ${CMAKE_INSTALL_PREFIX} on these from the beginning,
+ * forcing package maintainers to hard-code one of these locations,
+ * despite having a different ${CMAKE_INSTALL_PREFIX}.
+ *
+ * We'll keep these around for some time as fall-backs, as not to break
+ * existing packaging scripts.
+ */
+ { false, "/etc/Nuand/bladeRF/" },
+ { false, "/usr/share/Nuand/bladeRF/" },
+};
+
+static inline size_t get_home_dir(char *buf, size_t max_len)
+{
+ const char *home;
+
+ home = getenv("HOME");
+ if (home != NULL && strlen(home) > 0 && strlen(home) < max_len) {
+ strncat(buf, home, max_len);
+ } else {
+ const struct passwd *passwd;
+ const uid_t uid = getuid();
+ passwd = getpwuid(uid);
+ strncat(buf, passwd->pw_dir, max_len);
+ }
+
+ return strlen(buf);
+}
+
+static inline size_t get_install_dir(char *buf, size_t max_len)
+{
+ return 0;
+}
+
+#if BLADERF_OS_LINUX
+static inline size_t get_binary_dir(char *buf, size_t max_len)
+{
+ ssize_t result = readlink("/proc/self/exe", buf, max_len);
+
+ if (result > 0) {
+ return strip_last_path_entry(buf, DIR_DELIMETER);
+ } else {
+ return 0;
+ }
+}
+#elif BLADERF_OS_FREEBSD
+static inline size_t get_binary_dir(char *buf, size_t max_len)
+{
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ ssize_t result = sysctl(mib, 4, buf, &max_len, NULL, 0);
+
+ if (result > 0) {
+ return strip_last_path_entry(buf, DIR_DELIMETER);
+ } else {
+ return 0;
+ }
+}
+#elif BLADERF_OS_OSX
+#include <mach-o/dyld.h>
+static inline size_t get_binary_dir(char *buf, size_t max_len)
+{
+ uint32_t buf_size = max_len;
+ int status = _NSGetExecutablePath(buf, &buf_size);
+
+ if (status == 0) {
+ return strip_last_path_entry(buf, DIR_DELIMETER);
+ } else {
+ return 0;
+ }
+
+}
+#endif
+
+#elif BLADERF_OS_WINDOWS
+#define ACCESS_FILE_EXISTS 0
+#define DIR_DELIMETER '\\'
+#include <shlobj.h>
+
+static const struct search_path_entries search_paths[] = {
+ { false, "" },
+ { true, "/Nuand/bladeRF/" },
+};
+
+static inline size_t get_home_dir(char *buf, size_t max_len)
+{
+ /* Explicitly link to a runtime DLL to get SHGetKnownFolderPath.
+ * This deals with the case where we might not be able to staticly
+ * link it at build time, e.g. mingw32.
+ *
+ * http://msdn.microsoft.com/en-us/library/784bt7z7.aspx
+ */
+ typedef HRESULT (CALLBACK* LPFNSHGKFP_T)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR*);
+ HINSTANCE hDLL; // Handle to DLL
+ LPFNSHGKFP_T lpfnSHGetKnownFolderPath; // Function pointer
+
+ const KNOWNFOLDERID folder_id = FOLDERID_RoamingAppData;
+ PWSTR path;
+ HRESULT status;
+
+ assert(max_len < INT_MAX);
+
+ hDLL = LoadLibrary("Shell32");
+ if (hDLL == NULL) {
+ // DLL couldn't be loaded, bail out.
+ return 0;
+ }
+
+ lpfnSHGetKnownFolderPath = (LPFNSHGKFP_T)GetProcAddress(hDLL, "SHGetKnownFolderPath");
+
+ if (!lpfnSHGetKnownFolderPath) {
+ // Can't find the procedure we want. Free and bail.
+ FreeLibrary(hDLL);
+ return 0;
+ }
+
+ status = lpfnSHGetKnownFolderPath(&folder_id, 0, NULL, &path);
+ if (status == S_OK) {
+ WideCharToMultiByte(CP_ACP, 0, path, -1, buf, (int)max_len, NULL, NULL);
+ CoTaskMemFree(path);
+ }
+
+ FreeLibrary(hDLL);
+
+ return strlen(buf);
+}
+
+static inline size_t get_binary_dir(char *buf, size_t max_len)
+{
+ DWORD status;
+
+ assert(max_len <= MAXDWORD);
+ status = GetModuleFileName(NULL, buf, (DWORD) max_len);
+
+ if (status > 0) {
+ return strip_last_path_entry(buf, DIR_DELIMETER);
+ } else {
+ return 0;
+ }
+}
+
+static inline size_t get_install_dir(char *buf, size_t max_len)
+{
+ typedef LONG (CALLBACK* LPFNREGOPEN_T)(HKEY, LPCTSTR, DWORD, REGSAM, PHKEY);
+ typedef LONG (CALLBACK* LPFNREGQUERY_T)(HKEY, LPCTSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
+ typedef LONG (CALLBACK* LPFNREGCLOSE_T)(HKEY);
+
+ HINSTANCE hDLL; // Handle to DLL
+ LPFNREGOPEN_T lpfnRegOpenKeyEx; // Function pointer
+ LPFNREGQUERY_T lpfnRegQueryValueEx; // Function pointer
+ LPFNREGCLOSE_T lpfnRegCloseKey; // Function pointer
+ HKEY hk;
+ DWORD len;
+
+ assert(max_len < INT_MAX);
+
+ memset(buf, 0, max_len);
+ hDLL = LoadLibrary("Advapi32");
+ if (hDLL == NULL) {
+ // DLL couldn't be loaded, bail out.
+ return 0;
+ }
+
+ lpfnRegOpenKeyEx = (LPFNREGOPEN_T)GetProcAddress(hDLL, "RegOpenKeyExA");
+ if (!lpfnRegOpenKeyEx) {
+ // Can't find the procedure we want. Free and bail.
+ FreeLibrary(hDLL);
+ return 0;
+ }
+
+ lpfnRegQueryValueEx = (LPFNREGQUERY_T)GetProcAddress(hDLL, "RegQueryValueExA");
+ if (!lpfnRegQueryValueEx) {
+ // Can't find the procedure we want. Free and bail.
+ FreeLibrary(hDLL);
+ return 0;
+ }
+
+ lpfnRegCloseKey = (LPFNREGCLOSE_T)GetProcAddress(hDLL, "RegCloseKey");
+ if (!lpfnRegCloseKey) {
+ // Can't find the procedure we want. Free and bail.
+ FreeLibrary(hDLL);
+ return 0;
+ }
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Nuand LLC", 0, KEY_READ, &hk)) {
+ FreeLibrary(hDLL);
+ return 0;
+ }
+
+ len = (DWORD)max_len;
+ if (RegQueryValueEx(hk, "Path", 0, NULL, (LPBYTE) buf, &len) == ERROR_SUCCESS) {
+ if (len > 0 && len < max_len && buf[len - 1] != '\\')
+ strcat(buf, "\\");
+ } else
+ len = 0;
+
+ if (len) {
+ lpfnRegCloseKey(hk);
+ }
+
+ FreeLibrary(hDLL);
+
+ return len;
+}
+
+#else
+#error "Unknown OS or missing BLADERF_OS_* definition"
+#endif
+
+/* We're not using functions that use the *nix PATH_MAX (which is known to be
+ * problematic), or the WIN32 MAX_PATH. Therefore, we'll just use this
+ * arbitrary, but "sufficiently" large max buffer size for paths */
+#define PATH_MAX_LEN 4096
+
+char *file_find(const char *filename)
+{
+ size_t i, max_len;
+ char *full_path;
+ const char *env_var;
+
+ full_path = calloc(PATH_MAX_LEN+1, 1);
+ if (full_path == NULL) {
+ return NULL;
+ }
+
+ /* Check directory specified by environment variable */
+ env_var = getenv("BLADERF_SEARCH_DIR");
+ if (env_var != NULL) {
+ strncat(full_path, env_var, PATH_MAX_LEN - 1);
+ full_path[strlen(full_path)] = DIR_DELIMETER;
+
+ max_len = PATH_MAX_LEN - strlen(full_path);
+
+ if (max_len >= strlen(filename)) {
+ strncat(full_path, filename, max_len);
+ if (access(full_path, ACCESS_FILE_EXISTS) != -1) {
+ return full_path;
+ }
+ }
+ }
+
+ /* Check the directory containing the currently running binary */
+ memset(full_path, 0, PATH_MAX_LEN);
+ max_len = PATH_MAX_LEN - 1;
+
+ if (get_binary_dir(full_path, max_len) != 0) {
+ max_len -= strlen(full_path);
+
+ if (max_len >= strlen(filename)) {
+ strncat(full_path, filename, max_len);
+ if (access(full_path, ACCESS_FILE_EXISTS) != -1) {
+ return full_path;
+ }
+ } else {
+ log_debug("Skipping search for %s in %s. "
+ "Path would be truncated.\n",
+ filename, full_path);
+ }
+ }
+
+ /* Search our list of pre-determined paths */
+ for (i = 0; i < ARRAY_SIZE(search_paths); i++) {
+ memset(full_path, 0, PATH_MAX_LEN);
+ max_len = PATH_MAX_LEN;
+
+ if (search_paths[i].prepend_home) {
+ const size_t len = get_home_dir(full_path, max_len);
+
+ if (len != 0) {
+ max_len -= len;
+ } else {
+ continue;
+ }
+
+ }
+
+ strncat(full_path, search_paths[i].path, max_len);
+ max_len = PATH_MAX_LEN - strlen(full_path);
+
+ if (max_len >= strlen(filename)) {
+ strncat(full_path, filename, max_len);
+
+ if (access(full_path, ACCESS_FILE_EXISTS) != -1) {
+ return full_path;
+ }
+ } else {
+ log_debug("Skipping search for %s in %s. "
+ "Path would be truncated.\n",
+ filename, full_path);
+ }
+ }
+
+ /* Search the installation directory, if applicable */
+ if (get_install_dir(full_path, PATH_MAX_LEN)) {
+ max_len = PATH_MAX_LEN - strlen(full_path);
+
+ if (max_len >= strlen(filename)) {
+ strncat(full_path, filename, max_len);
+ if (access(full_path, ACCESS_FILE_EXISTS) != -1) {
+ return full_path;
+ }
+ } else {
+ log_debug("Skipping search for %s in %s. "
+ "Path would be truncated.\n",
+ filename, full_path);
+ }
+ }
+
+ free(full_path);
+ return NULL;
+}
diff --git a/Radio/HW/BladeRF/src/helpers/file.h b/Radio/HW/BladeRF/src/helpers/file.h
new file mode 100644
index 0000000..a1db20a
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/file.h
@@ -0,0 +1,97 @@
+/**
+ * @file file.h
+ *
+ * @brief Wrappers around misc. file operations.
+ *
+ * These are collected here so that they may easily be dummied out for NIOS
+ * headless builds in the future.
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013 Nuand LLC
+ * Copyright (C) 2013 Daniel Gröber <dxld ÄT darkboxed DOT org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HELPERS_FILE_H_
+#define HELPERS_FILE_H_
+
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * Read file contents into a buffer allocated internally and returned to the
+ * caller through `buf'.
+ *
+ * The caller is responsible for freeing the allocated buffer
+ *
+ * @param[in] filename File open
+ * @param[out] buf Upon success, this will point to a heap-allocated
+ * buffer containing the file contents
+ * @parma[out] size Upon success, this will be updated to reflect the
+ * size of the buffered file
+ *
+ * @return 0 on success, negative BLADERF_ERR_* value on failure
+ */
+int file_read_buffer(const char *filename, uint8_t **buf, size_t *size);
+
+/**
+ * Write to an open file stream.
+ *
+ * @param[in] f Open file stream.
+ * @param[in] buf Data to write to the stream.
+ * @parma[in] len Number of bytes to write to the stream.
+ *
+ * @return 0 on success, negative BLADERF_ERR_* value on failure
+ */
+int file_write(FILE *f, uint8_t *buf, size_t len);
+
+/**
+ * Read data from an open file stream.
+ *
+ * @param[in] f Open file stream.
+ * @param[out] buf Buffer to fill with data read.
+ * @parma[in] len Number of bytes to read. If EOF is encountered
+ * before this many bytes have been read will return
+ * an error.
+ *
+ * @return 0 on success, negative BLADERF_ERR_* value on failure
+ */
+int file_read(FILE *f, char *buf, size_t len);
+
+/**
+ * Determine the size of an open file stream.
+ *
+ * @param[in] f Open file stream.
+ *
+ * @return positive size of file on success, negative BLADERF_ERR_* value on
+ * failure
+ */
+ssize_t file_size(FILE *f);
+
+/**
+ * Search for the specified filename in bladeRF config directories. If found,
+ * the full path is returned. There is a chance that the file will be removed
+ * in between this call indicating it exists and attempting to open it.
+ *
+ * @param[in] filename File to search for
+ *
+ * @return Full path if the file is found, NULL otherwise.
+ */
+char *file_find(const char *filename);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/helpers/have_cap.h b/Radio/HW/BladeRF/src/helpers/have_cap.h
new file mode 100644
index 0000000..f6ed471
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/have_cap.h
@@ -0,0 +1,43 @@
+/**
+ * @file have_cap.h
+ *
+ * @brief Convenience wrapper for testing capabilities mask
+ *
+ * Copyright (C) 2020 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef HAVE_CAP_H_
+#define HAVE_CAP_H_
+
+#include <stdint.h>
+
+/**
+ * Convenience wrapper for testing capabilities mask
+ */
+static inline bool have_cap(uint64_t capabilities, uint64_t capability)
+{
+ return (capabilities & capability) != 0;
+}
+
+/**
+ * Convenience wrapper for testing capabilities mask
+ */
+static inline bool have_cap_dev(struct bladerf *dev, uint64_t capability)
+{
+ uint64_t capabilities = dev->board->get_capabilities(dev);
+ return (capabilities & capability) != 0;
+}
+#endif // HAVE_CAP_H_
diff --git a/Radio/HW/BladeRF/src/helpers/interleave.c b/Radio/HW/BladeRF/src/helpers/interleave.c
new file mode 100644
index 0000000..0989c4c
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/interleave.c
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2017 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include <libbladeRF.h>
+
+#include "helpers/interleave.h"
+
+size_t _interleave_calc_num_channels(bladerf_channel_layout layout)
+{
+ switch (layout) {
+ case BLADERF_RX_X1:
+ case BLADERF_TX_X1:
+ return 1;
+ case BLADERF_RX_X2:
+ case BLADERF_TX_X2:
+ return 2;
+ }
+
+ return 0;
+}
+
+size_t _interleave_calc_bytes_per_sample(bladerf_format format)
+{
+ switch (format) {
+ case BLADERF_FORMAT_SC8_Q7:
+ case BLADERF_FORMAT_SC8_Q7_META:
+ return 2;
+
+ case BLADERF_FORMAT_SC16_Q11:
+ case BLADERF_FORMAT_SC16_Q11_META:
+ case BLADERF_FORMAT_PACKET_META:
+ return 4;
+ }
+
+ return 0;
+}
+
+size_t _interleave_calc_metadata_bytes(bladerf_format format)
+{
+ switch (format) {
+ case BLADERF_FORMAT_SC8_Q7_META:
+ case BLADERF_FORMAT_SC16_Q11_META:
+ case BLADERF_FORMAT_PACKET_META:
+ return 0x10;
+ case BLADERF_FORMAT_SC8_Q7:
+ case BLADERF_FORMAT_SC16_Q11:
+ return 0;
+ }
+
+ return 0;
+}
+
+int _interleave_interleave_buf(bladerf_channel_layout layout,
+ bladerf_format format,
+ unsigned int buffer_size,
+ void *samples)
+{
+ void *buf;
+ uint8_t *srcptr, *dstptr;
+ size_t num_channels = _interleave_calc_num_channels(layout);
+ size_t samp_size, meta_size, samps_per_ch;
+ size_t srcidx, dstidx, samp, ch;
+
+ // Easy:
+ if (num_channels < 2) {
+ return 0;
+ }
+
+ // Placeholder for an actually efficient algorithm
+ samp_size = _interleave_calc_bytes_per_sample(format);
+ meta_size = _interleave_calc_metadata_bytes(format);
+ samps_per_ch = buffer_size / num_channels;
+ buf = malloc(samp_size * buffer_size);
+ srcptr = samples;
+ dstptr = buf;
+
+ if (NULL == buf) {
+ return BLADERF_ERR_MEM;
+ }
+
+ // Copy metadata if applicable
+ if (meta_size > 0) {
+ memcpy(dstptr, srcptr, meta_size);
+ srcptr += meta_size;
+ dstptr += meta_size;
+ samps_per_ch -= (meta_size / samp_size / num_channels);
+ }
+
+ // Iterate...
+ for (ch = 0; ch < num_channels; ++ch) {
+ srcidx = samps_per_ch * ch;
+ for (samp = 0; samp < samps_per_ch; ++samp) {
+ dstidx = (samp * num_channels) + ch;
+ memcpy(dstptr + (dstidx * samp_size),
+ srcptr + ((srcidx + samp) * samp_size),
+ samp_size);
+ }
+ }
+
+ // Copy back...
+ memcpy(samples, buf, buffer_size * samp_size);
+
+ // Done
+ free(buf);
+
+ return 0;
+}
+
+int _interleave_deinterleave_buf(bladerf_channel_layout layout,
+ bladerf_format format,
+ unsigned int buffer_size,
+ void *samples)
+{
+ void *buf;
+ uint8_t *srcptr, *dstptr;
+ size_t num_channels = _interleave_calc_num_channels(layout);
+ size_t samp_size, meta_size, samps_per_ch;
+ size_t srcidx, dstidx, samp, ch;
+
+ // Easy:
+ if (num_channels < 2) {
+ return 0;
+ }
+
+ // Placeholder for an actually efficient algorithm
+ samp_size = _interleave_calc_bytes_per_sample(format);
+ meta_size = _interleave_calc_metadata_bytes(format);
+ samps_per_ch = buffer_size / num_channels;
+ buf = malloc(samp_size * buffer_size);
+ srcptr = samples;
+ dstptr = buf;
+
+ if (NULL == buf) {
+ return BLADERF_ERR_MEM;
+ }
+
+ // Copy metadata if applicable
+ if (meta_size > 0) {
+ memcpy(dstptr, srcptr, meta_size);
+ srcptr += meta_size;
+ dstptr += meta_size;
+ samps_per_ch -= (meta_size / samp_size / num_channels);
+ }
+
+ // Iterate...
+ for (samp = 0; samp < samps_per_ch; ++samp) {
+ srcidx = num_channels * samp;
+ for (ch = 0; ch < num_channels; ++ch) {
+ dstidx = (samps_per_ch * ch) + samp;
+ memcpy(dstptr + (dstidx * samp_size),
+ srcptr + ((srcidx + ch) * samp_size), samp_size);
+ }
+ }
+
+ // Copy back...
+ memcpy(samples, buf, buffer_size * samp_size);
+
+ // Done
+ free(buf);
+
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/src/helpers/interleave.h b/Radio/HW/BladeRF/src/helpers/interleave.h
new file mode 100644
index 0000000..526dc41
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/interleave.h
@@ -0,0 +1,44 @@
+/**
+ * @file interleave.h
+ *
+ * This file is not part of the API and may be changed at any time.
+ * If you're interfacing with libbladeRF, DO NOT use this file.
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2017 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HELPERS_INTERLEAVE_H_
+#define HELPERS_INTERLEAVE_H_
+
+size_t _interleave_calc_bytes_per_sample(bladerf_format format);
+size_t _interleave_calc_metadata_bytes(bladerf_format format);
+size_t _interleave_calc_num_channels(bladerf_channel_layout layout);
+
+int _interleave_interleave_buf(bladerf_channel_layout layout,
+ bladerf_format format,
+ unsigned int buffer_size,
+ void *samples);
+
+int _interleave_deinterleave_buf(bladerf_channel_layout layout,
+ bladerf_format format,
+ unsigned int buffer_size,
+ void *samples);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/helpers/timeout.c b/Radio/HW/BladeRF/src/helpers/timeout.c
new file mode 100644
index 0000000..d0f680b
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/timeout.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "host_config.h"
+
+#if BLADERF_OS_WINDOWS || BLADERF_OS_OSX
+#include "clock_gettime.h"
+#else
+#include <time.h>
+#endif
+
+#include <libbladeRF.h>
+
+int populate_abs_timeout(struct timespec *t, unsigned int timeout_ms)
+{
+ static const int nsec_per_sec = 1000 * 1000 * 1000;
+ const unsigned int timeout_sec = timeout_ms / 1000;
+ int status;
+
+ status = clock_gettime(CLOCK_REALTIME, t);
+ if (status != 0) {
+ return BLADERF_ERR_UNEXPECTED;
+ } else {
+ t->tv_sec += timeout_sec;
+ t->tv_nsec += (timeout_ms % 1000) * 1000 * 1000;
+
+ if (t->tv_nsec >= nsec_per_sec) {
+ t->tv_sec += t->tv_nsec / nsec_per_sec;
+ t->tv_nsec %= nsec_per_sec;
+ }
+
+ return 0;
+ }
+}
diff --git a/Radio/HW/BladeRF/src/helpers/timeout.h b/Radio/HW/BladeRF/src/helpers/timeout.h
new file mode 100644
index 0000000..1b6cb7c
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/timeout.h
@@ -0,0 +1,40 @@
+/**
+ * @file timeout.h
+ *
+ * This file is not part of the API and may be changed at any time.
+ * If you're interfacing with libbladeRF, DO NOT use this file.
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013-2015 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HELPERS_TIMEOUT_H_
+#define HELPERS_TIMEOUT_H_
+
+/**
+ * Populate the provided timeval structure for the specified timeout
+ *
+ * @param[out] t_abs Absolute timeout structure to populate
+ * @param[in] timeout_ms Desired timeout in ms.
+ *
+ * 0 on success, BLADERF_ERR_UNEXPECTED on failure
+ */
+int populate_abs_timeout(struct timespec *t_abs, unsigned int timeout_ms);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/helpers/version.c b/Radio/HW/BladeRF/src/helpers/version.c
new file mode 100644
index 0000000..a378d23
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/version.c
@@ -0,0 +1,177 @@
+/**
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014-2015 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "log.h"
+#include "rel_assert.h"
+
+#include "helpers/version.h"
+
+bool version_equal(const struct bladerf_version *v1,
+ const struct bladerf_version *v2)
+{
+ return v1->major == v2->major &&
+ v1->minor == v2->minor &&
+ v1->patch == v2->patch;
+}
+
+bool version_greater_or_equal(const struct bladerf_version *v1,
+ const struct bladerf_version *v2)
+{
+ return version_fields_greater_or_equal(v1, v2->major, v2->minor, v2->patch);
+}
+
+bool version_less_than(const struct bladerf_version *v1,
+ const struct bladerf_version *v2)
+{
+ return version_fields_less_than(v1, v2->major, v2->minor, v2->patch);
+}
+
+bool version_fields_greater_or_equal(const struct bladerf_version *version,
+ unsigned int major, unsigned int minor,
+ unsigned int patch)
+{
+ if (version->major > major) {
+ return true;
+ } else if ( (version->major == major) && (version->minor > minor) ) {
+ return true;
+ } else if ((version->major == major) &&
+ (version->minor == minor) &&
+ (version->patch >= patch) ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool version_fields_less_than(const struct bladerf_version *version,
+ unsigned int major, unsigned int minor,
+ unsigned int patch)
+{
+ return !version_fields_greater_or_equal(version, major, minor, patch);
+}
+
+static const struct compat *find_fw_compat(const struct version_compat_table *fw_compat_table,
+ const struct bladerf_version *fw_version)
+{
+ const struct compat *newest_compat = &fw_compat_table->table[0];
+ size_t i;
+
+ /* Version is newer than what's in our table - complain */
+ if (version_less_than(&newest_compat->ver, fw_version)) {
+ log_info("Firmware version (v%u.%u.%u) is newer than entries in "
+ "libbladeRF's compatibility table. Please update libbladeRF "
+ "if problems arise.\n",
+ fw_version->major, fw_version->minor, fw_version->patch);
+ return newest_compat;
+ }
+
+ for (i = 0; i < fw_compat_table->len; i++) {
+ if (version_equal(fw_version, &fw_compat_table->table[i].ver)) {
+ return &fw_compat_table->table[i];
+ }
+ }
+
+ return NULL;
+}
+
+static const struct compat *find_fpga_compat(const struct version_compat_table *fpga_compat_table,
+ const struct bladerf_version *fpga_version)
+{
+ const struct compat *newest_compat = &fpga_compat_table->table[0];
+ size_t i;
+
+ /* Device's FPGA is newer than what's in our table - complain */
+ if (version_less_than(&newest_compat->ver, fpga_version)) {
+ log_info("FPGA version (v%u.%u.%u) is newer than entries in "
+ "libbladeRF's compatibility table. Please update libbladeRF "
+ "if problems arise.\n",
+ fpga_version->major, fpga_version->minor, fpga_version->patch);
+ return newest_compat;
+ }
+
+ for (i = 0; i < fpga_compat_table->len; i++) {
+ if (version_equal(fpga_version, &fpga_compat_table->table[i].ver)) {
+ return &fpga_compat_table->table[i];
+ }
+ }
+
+ return NULL;
+}
+
+int version_check_fw(const struct version_compat_table *fw_compat_table,
+ const struct bladerf_version *fw_version,
+ struct bladerf_version *required_fw_version)
+{
+ const struct bladerf_version *oldest_version = &fw_compat_table->table[fw_compat_table->len-1].ver;
+
+ if (required_fw_version) {
+ *required_fw_version = *oldest_version;
+ }
+
+ if (version_greater_or_equal(fw_version, oldest_version)) {
+ return 0;
+ }
+
+ return BLADERF_ERR_UPDATE_FW;
+}
+
+int version_check(const struct version_compat_table *fw_compat_table,
+ const struct version_compat_table *fpga_compat_table,
+ const struct bladerf_version *fw_version,
+ const struct bladerf_version *fpga_version,
+ struct bladerf_version *required_fw_version,
+ struct bladerf_version *required_fpga_version)
+{
+ const struct compat *fw_compat = find_fw_compat(fw_compat_table, fw_version);
+ const struct compat *fpga_compat = find_fpga_compat(fpga_compat_table, fpga_version);
+
+ if (fw_compat == NULL) {
+ log_debug("%s is missing FW version compat table entry?\n",
+ __FUNCTION__);
+ return BLADERF_ERR_UPDATE_FW;
+ } else if (fpga_compat == NULL) {
+ log_debug("%s is missing FPGA version compat table entry?\n",
+ __FUNCTION__);
+ return BLADERF_ERR_UPDATE_FPGA;
+ }
+
+ if (required_fw_version) {
+ *required_fw_version = fpga_compat->requires;
+ }
+ if (required_fpga_version) {
+ *required_fpga_version = fw_compat->requires;
+ }
+
+ /* Check if the FPGA meets the minimum requirements dictated by the
+ * firmware version */
+ if (version_less_than(fpga_version, &fw_compat->requires)) {
+ return BLADERF_ERR_UPDATE_FPGA;
+ }
+
+ /* Check if the firmware version meets the minimum requirements dictated
+ * by the FPGA version */
+ if (version_less_than(fw_version, &fpga_compat->requires)) {
+ return BLADERF_ERR_UPDATE_FW;
+ }
+
+ return 0;
+}
+
diff --git a/Radio/HW/BladeRF/src/helpers/version.h b/Radio/HW/BladeRF/src/helpers/version.h
new file mode 100644
index 0000000..b4e4559
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/version.h
@@ -0,0 +1,142 @@
+/**
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HELPERS_VERSION_H_
+#define HELPERS_VERSION_H_
+
+#include <libbladeRF.h>
+
+#define BLADERF_VERSION_STR_MAX 32
+
+/**
+ * Test if two versions are equal. The "describe" field is not checked.
+ *
+ * @return true if equal, false otherwise
+ */
+bool version_equal(const struct bladerf_version *v1,
+ const struct bladerf_version *v2);
+
+/**
+ * Check if version v1 is greater than or equal to version v2.
+ *
+ * @param[in] v1 First version
+ * @param[in] v2 Second version
+ *
+ * @return true for greater or equal than, false otherwise
+ */
+bool version_greater_or_equal(const struct bladerf_version *v1,
+ const struct bladerf_version *v2);
+
+/**
+ * Check if version v1 is less than version v2.
+ *
+ * @param[in] v1 First version
+ * @param[in] v2 Second version
+ *
+ * @return true for less than, false otherwise
+ */
+bool version_less_than(const struct bladerf_version *v1,
+ const struct bladerf_version *v2);
+
+/**
+ * Check if version in the provided structure is greater or equal to
+ * the version specified by the provided major, minor, and patch values
+ *
+ * @param[in] version Version structure to check
+ * @param[in] major Minor version
+ * @param[in] minor Minor version
+ * @param[in] patch Patch version
+ *
+ * @return true for greater or equal than, false otherwise
+ */
+bool version_fields_greater_or_equal(const struct bladerf_version *version,
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch);
+
+/**
+ * Check if version in the provided structure is less than
+ * the version specied by the provided major, minor, and patch values
+ *
+ * @param[in] version Version structure to check
+ * @param[in] major Minor version
+ * @param[in] minor Minor version
+ * @param[in] patch Patch version
+ *
+ * @return true for less than, false otherwise
+ */
+bool version_fields_less_than(const struct bladerf_version *version,
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch);
+
+
+/* Version compatibility table structure. */
+struct version_compat_table {
+ const struct compat {
+ struct bladerf_version ver;
+ struct bladerf_version requires;
+ } * table;
+ unsigned int len;
+};
+
+/**
+ * Check if the firmware version is sufficient for the current libbladeRF
+ * version. If it's not, the user will need to use the bootloader to flash a
+ * newer version.
+ *
+ * @param[in] fw_compat_table Firmware-FPGA version compat. table
+ * @param[in] fw_version Firmware version
+ * @param[out] required_fw_version If not-NULL, populated with minimum
+ * required firmware version
+ *
+ * @return 0 if the FW version is sufficient for normal operation,
+ * BLADERF_ERR_UPDATE_FW if a firmware update is required.
+ */
+int version_check_fw(const struct version_compat_table *fw_compat_table,
+ const struct bladerf_version *fw_version,
+ struct bladerf_version *required_fw_version);
+
+/**
+ * Check if the firmware and FPGA versions are sufficient and compatible.
+ *
+ * @param[in] fw_compat_table Firmware-FPGA version compat. table
+ * @param[in] fpga_compat_table FPGA-Firmware version compat. table
+ * @param[in] fw_version Firmware version
+ * @param[in] fpga_version Firmware version
+ * @param[out] required_fw_version If not-NULL, populated with minimum
+ * required firmware version
+ * @param[out] required_fpga_version If not-NULL, populated with minimum
+ * required FPGA version
+ *
+ * @return 0 if the FPGA version is sufficient for normal operation,
+ * BLADERF_ERR_UPDATE_FPGA if the firmware requires a newer FPGA,
+ * BLADERF_ERR_UPDATE_FW if a firmware update is required to support
+ * the currently loaded FPGA.
+ */
+int version_check(const struct version_compat_table *fw_compat_table,
+ const struct version_compat_table *fpga_compat_table,
+ const struct bladerf_version *fw_version,
+ const struct bladerf_version *fpga_version,
+ struct bladerf_version *required_fw_version,
+ struct bladerf_version *required_fpga_version);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/helpers/wallclock.c b/Radio/HW/BladeRF/src/helpers/wallclock.c
new file mode 100644
index 0000000..c75ae1e
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/wallclock.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2013-2018 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "wallclock.h"
+#include "host_config.h"
+
+#if BLADERF_OS_WINDOWS || BLADERF_OS_OSX
+#include "clock_gettime.h"
+#else
+#include <time.h>
+#endif
+
+uint64_t wallclock_get_current_nsec()
+{
+ static const int nsec_per_sec = 1000 * 1000 * 1000;
+ struct timespec t;
+ int status;
+ uint64_t rv;
+
+ status = clock_gettime(CLOCK_REALTIME, &t);
+ if (status != 0) {
+ rv = 0;
+ } else {
+ rv = (t.tv_sec * nsec_per_sec);
+ rv += (t.tv_nsec);
+ }
+
+ return rv;
+}
diff --git a/Radio/HW/BladeRF/src/helpers/wallclock.h b/Radio/HW/BladeRF/src/helpers/wallclock.h
new file mode 100644
index 0000000..d6fcbb9
--- /dev/null
+++ b/Radio/HW/BladeRF/src/helpers/wallclock.h
@@ -0,0 +1,29 @@
+/**
+ * @file wallclock.h
+ *
+ * @brief System clock access helpers
+ *
+ * Copyright (C) 2013-2018 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef WALLCLOCK_H_
+#define WALLCLOCK_H_
+
+#include <stdint.h>
+
+uint64_t wallclock_get_current_nsec();
+
+#endif // WALLCLOCK_H_