summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/src/helpers/configfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/HW/BladeRF/src/helpers/configfile.c')
-rw-r--r--Radio/HW/BladeRF/src/helpers/configfile.c342
1 files changed, 342 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;
+}