diff options
Diffstat (limited to 'Radio/HW/BladeRF/src/helpers')
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/configfile.c | 342 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/configfile.h | 27 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/file.c | 511 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/file.h | 97 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/have_cap.h | 43 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/interleave.c | 182 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/interleave.h | 44 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/timeout.c | 52 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/timeout.h | 40 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/version.c | 177 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/version.h | 142 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/wallclock.c | 47 | ||||
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/wallclock.h | 29 |
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_ |