diff options
Diffstat (limited to 'Radio/HW/BladeRF/src/helpers/configfile.c')
-rw-r--r-- | Radio/HW/BladeRF/src/helpers/configfile.c | 342 |
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; +} |