summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/src/expansion
diff options
context:
space:
mode:
authorArturs Artamonovs <arturs.artamonovs@protonmail.com>2024-11-03 15:56:55 +0000
committerArturs Artamonovs <arturs.artamonovs@protonmail.com>2024-11-03 15:56:55 +0000
commitcf4444e7390365df43ecbd3d130015c1e06ef88f (patch)
tree8a6eb114135a04d5efd5af213577b4fac47532ae /Radio/HW/BladeRF/src/expansion
parentca50c0f64f1b2fce46b4cb83ed111854bac13852 (diff)
downloadPrySDR-cf4444e7390365df43ecbd3d130015c1e06ef88f.tar.gz
PrySDR-cf4444e7390365df43ecbd3d130015c1e06ef88f.zip
BladeRF library compiles
Diffstat (limited to 'Radio/HW/BladeRF/src/expansion')
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb100.c98
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb100.h47
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb200.c543
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb200.h105
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb300.c299
-rw-r--r--Radio/HW/BladeRF/src/expansion/xb300.h94
6 files changed, 1186 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/src/expansion/xb100.c b/Radio/HW/BladeRF/src/expansion/xb100.c
new file mode 100644
index 0000000..b432616
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb100.c
@@ -0,0 +1,98 @@
+/*
+ * 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
+ */
+
+#include "xb100.h"
+
+#include "log.h"
+
+int xb100_attach(struct bladerf *dev)
+{
+ return 0;
+}
+
+void xb100_detach(struct bladerf *dev)
+{
+}
+
+int xb100_enable(struct bladerf *dev, bool enable)
+{
+ int status = 0;
+
+ const uint32_t mask =
+ BLADERF_XB100_LED_D1 |
+ BLADERF_XB100_LED_D2 |
+ BLADERF_XB100_LED_D3 |
+ BLADERF_XB100_LED_D4 |
+ BLADERF_XB100_LED_D5 |
+ BLADERF_XB100_LED_D6 |
+ BLADERF_XB100_LED_D7 |
+ BLADERF_XB100_LED_D8 |
+ BLADERF_XB100_TLED_RED |
+ BLADERF_XB100_TLED_GREEN |
+ BLADERF_XB100_TLED_BLUE;
+
+ const uint32_t outputs = mask;
+ const uint32_t default_values = mask;
+
+ if (enable) {
+ status = dev->backend->expansion_gpio_dir_write(dev, mask, outputs);
+ if (status == 0) {
+ status = dev->backend->expansion_gpio_write(dev, mask, default_values);
+ }
+ }
+
+ return status;
+}
+
+int xb100_init(struct bladerf *dev)
+{
+ return 0;
+}
+
+int xb100_gpio_read(struct bladerf *dev, uint32_t *val)
+{
+ return dev->backend->expansion_gpio_read(dev, val);
+}
+
+int xb100_gpio_write(struct bladerf *dev, uint32_t val)
+{
+ return dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+}
+
+int xb100_gpio_masked_write(struct bladerf *dev, uint32_t mask, uint32_t val)
+{
+ return dev->backend->expansion_gpio_write(dev, mask, val);
+}
+
+int xb100_gpio_dir_read(struct bladerf *dev, uint32_t *val)
+{
+ return dev->backend->expansion_gpio_dir_read(dev, val);
+}
+
+int xb100_gpio_dir_write(struct bladerf *dev, uint32_t val)
+{
+ return xb100_gpio_dir_masked_write(dev, 0xffffffff, val);
+}
+
+int xb100_gpio_dir_masked_write(struct bladerf *dev, uint32_t mask, uint32_t val)
+{
+ return dev->backend->expansion_gpio_dir_write(dev, mask, val);
+}
diff --git a/Radio/HW/BladeRF/src/expansion/xb100.h b/Radio/HW/BladeRF/src/expansion/xb100.h
new file mode 100644
index 0000000..2a49830
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb100.h
@@ -0,0 +1,47 @@
+/**
+ * @file xb.h
+ *
+ * @brief XB-100 support
+ *
+ * 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 EXPANSION_XB100_H_
+#define EXPANSION_XB100_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "board/board.h"
+
+int xb100_attach(struct bladerf *dev);
+void xb100_detach(struct bladerf *dev);
+int xb100_enable(struct bladerf *dev, bool enable);
+int xb100_init(struct bladerf *dev);
+int xb100_gpio_read(struct bladerf *dev, uint32_t *val);
+int xb100_gpio_write(struct bladerf *dev, uint32_t val);
+int xb100_gpio_masked_write(struct bladerf *dev, uint32_t mask, uint32_t val);
+int xb100_gpio_dir_read(struct bladerf *dev, uint32_t *val);
+int xb100_gpio_dir_write(struct bladerf *dev, uint32_t val);
+int xb100_gpio_dir_masked_write(struct bladerf *dev,
+ uint32_t mask,
+ uint32_t val);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/expansion/xb200.c b/Radio/HW/BladeRF/src/expansion/xb200.c
new file mode 100644
index 0000000..1e6dba2
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb200.c
@@ -0,0 +1,543 @@
+/*
+ * 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
+ */
+
+#include "xb200.h"
+
+#include "driver/si5338.h"
+#include "lms.h"
+#include "rel_assert.h"
+#include "log.h"
+
+#define BLADERF_XB_CONFIG_TX_PATH_MIX 0x04
+#define BLADERF_XB_CONFIG_TX_PATH_BYPASS 0x08
+#define BLADERF_XB_CONFIG_TX_BYPASS 0x04
+#define BLADERF_XB_CONFIG_TX_BYPASS_N 0x08
+#define BLADERF_XB_CONFIG_TX_BYPASS_MASK 0x0C
+#define BLADERF_XB_CONFIG_RX_PATH_MIX 0x10
+#define BLADERF_XB_CONFIG_RX_PATH_BYPASS 0x20
+#define BLADERF_XB_CONFIG_RX_BYPASS 0x10
+#define BLADERF_XB_CONFIG_RX_BYPASS_N 0x20
+#define BLADERF_XB_CONFIG_RX_BYPASS_MASK 0x30
+
+#define BLADERF_XB_RF_ON 0x0800
+#define BLADERF_XB_TX_ENABLE 0x1000
+#define BLADERF_XB_RX_ENABLE 0x2000
+
+#define BLADERF_XB_TX_RF_SW2 0x04000000
+#define BLADERF_XB_TX_RF_SW1 0x08000000
+#define BLADERF_XB_TX_MASK 0x0C000000
+#define BLADERF_XB_TX_SHIFT 26
+
+#define BLADERF_XB_RX_RF_SW2 0x10000000
+#define BLADERF_XB_RX_RF_SW1 0x20000000
+#define BLADERF_XB_RX_MASK 0x30000000
+#define BLADERF_XB_RX_SHIFT 28
+
+struct xb200_xb_data {
+ /* Track filterbank selection for RX and TX auto-selection */
+ bladerf_xb200_filter auto_filter[2];
+};
+
+int xb200_attach(struct bladerf *dev)
+{
+ struct xb200_xb_data *xb_data;
+ int status = 0;
+ uint32_t val;
+ uint8_t val8;
+ unsigned int muxout = 6;
+ const char *mux_lut[] = { "THREE-STATE OUTPUT",
+ "DVdd",
+ "DGND",
+ "R COUNTER OUTPUT",
+ "N DIVIDER OUTPUT",
+ "ANALOG LOCK DETECT",
+ "DIGITAL LOCK DETECT",
+ "RESERVED" };
+
+ xb_data = calloc(1, sizeof(struct xb200_xb_data));
+ if (xb_data == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ xb_data->auto_filter[BLADERF_CHANNEL_RX(0)] = -1;
+ xb_data->auto_filter[BLADERF_CHANNEL_TX(0)] = -1;
+
+ dev->xb_data = xb_data;
+
+ log_debug(" Attaching transverter board\n");
+ status = dev->backend->si5338_read(dev, 39, &val8);
+ if (status < 0) {
+ goto error;
+ }
+ val8 |= 2;
+ if ((status = dev->backend->si5338_write(dev, 39, val8))) {
+ goto error;
+ }
+ if ((status = dev->backend->si5338_write(dev, 34, 0x22))) {
+ goto error;
+ }
+ if ((status = dev->backend->config_gpio_read(dev, &val))) {
+ goto error;
+ }
+ val |= 0x80000000;
+ if ((status = dev->backend->config_gpio_write(dev, val))) {
+ goto error;
+ }
+ if ((status = dev->backend->expansion_gpio_read(dev, &val))) {
+ goto error;
+ }
+
+ if ((status = dev->backend->expansion_gpio_dir_write(dev, 0xffffffff,
+ 0x3C00383E))) {
+ goto error;
+ }
+
+ if ((status = dev->backend->expansion_gpio_write(dev, 0xffffffff, 0x800))) {
+ goto error;
+ }
+
+ // Load ADF4351 registers via SPI
+ // Refer to ADF4351 reference manual for register set
+ // The LO is set to a Int-N 1248MHz +3dBm tone
+ // Registers are written in order from 5 downto 0
+ if ((status = dev->backend->xb_spi(dev, 0x580005))) {
+ goto error;
+ }
+ if ((status = dev->backend->xb_spi(dev, 0x99A16C))) {
+ goto error;
+ }
+ if ((status = dev->backend->xb_spi(dev, 0xC004B3))) {
+ goto error;
+ }
+ log_debug(" MUXOUT: %s\n", mux_lut[muxout]);
+
+ if ((status = dev->backend->xb_spi(dev, 0x60008E42 | (1 << 8) |
+ (muxout << 26)))) {
+ goto error;
+ }
+ if ((status = dev->backend->xb_spi(dev, 0x08008011))) {
+ goto error;
+ }
+ if ((status = dev->backend->xb_spi(dev, 0x00410000))) {
+ goto error;
+ }
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (!status && (val & 0x1))
+ log_debug(" MUXOUT Bit set: OK\n");
+ else {
+ log_debug(" MUXOUT Bit not set: FAIL\n");
+ }
+ if ((status =
+ dev->backend->expansion_gpio_write(dev, 0xffffffff, 0x3C000800))) {
+ goto error;
+ }
+
+ return 0;
+
+error:
+ free(dev->xb_data);
+ dev->xb_data = NULL;
+ return status;
+}
+
+void xb200_detach(struct bladerf *dev)
+{
+ if (dev->xb_data) {
+ free(dev->xb_data);
+ dev->xb_data = NULL;
+ }
+}
+
+int xb200_enable(struct bladerf *dev, bool enable)
+{
+ int status;
+ uint32_t val, orig;
+
+ status = dev->backend->expansion_gpio_read(dev, &orig);
+ if (status)
+ return status;
+
+ val = orig;
+ if (enable)
+ val |= BLADERF_XB_RF_ON;
+ else
+ val &= ~BLADERF_XB_RF_ON;
+
+ if (status || (val == orig))
+ return status;
+
+ return dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+}
+
+int xb200_init(struct bladerf *dev)
+{
+ int status;
+
+ log_verbose( "Setting RX path\n" );
+ status = xb200_set_path(dev, BLADERF_CHANNEL_RX(0), BLADERF_XB200_BYPASS);
+ if (status != 0) {
+ return status;
+ }
+
+ log_verbose( "Setting TX path\n" );
+ status = xb200_set_path(dev, BLADERF_CHANNEL_TX(0), BLADERF_XB200_BYPASS);
+ if (status != 0) {
+ return status;
+ }
+
+ log_verbose( "Setting RX filter\n" );
+ status = xb200_set_filterbank(dev, BLADERF_CHANNEL_RX(0), BLADERF_XB200_AUTO_1DB);
+ if (status != 0) {
+ return status;
+ }
+
+ log_verbose( "Setting TX filter\n" );
+ status = xb200_set_filterbank(dev, BLADERF_CHANNEL_TX(0), BLADERF_XB200_AUTO_1DB);
+ if (status != 0) {
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * Validate XB-200 filter selection
+ *
+ * @param[in] f Filter supplied by API user.
+ *
+ * @return 0 for a valid enumeration value, BLADERF_ERR_INVAL otherwise.
+ */
+static int check_xb200_filter(bladerf_xb200_filter f)
+{
+ int status;
+
+ switch (f) {
+ case BLADERF_XB200_50M:
+ case BLADERF_XB200_144M:
+ case BLADERF_XB200_222M:
+ case BLADERF_XB200_CUSTOM:
+ case BLADERF_XB200_AUTO_3DB:
+ case BLADERF_XB200_AUTO_1DB:
+ status = 0;
+ break;
+
+ default:
+ log_debug("Invalid XB200 filter: %d\n", f);
+ status = BLADERF_ERR_INVAL;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * Validate XB-200 path selection
+ *
+ * @param[in] p Path supplied by API user.
+ *
+ * @return 0 for a valid enumeration value, BLADERF_ERR_INVAL otherwise.
+ */
+static int check_xb200_path(bladerf_xb200_path p)
+{
+ int status;
+
+ switch (p) {
+ case BLADERF_XB200_BYPASS:
+ case BLADERF_XB200_MIX:
+ status = 0;
+ break;
+
+ default:
+ status = BLADERF_ERR_INVAL;
+ log_debug("Invalid XB200 path: %d\n", p);
+ break;
+ }
+
+ return status;
+}
+int xb200_get_filterbank(struct bladerf *dev, bladerf_channel ch,
+ bladerf_xb200_filter *filter) {
+ int status;
+ uint32_t val;
+ unsigned int shift;
+
+ if (ch != BLADERF_CHANNEL_RX(0) && ch != BLADERF_CHANNEL_TX(0))
+ return BLADERF_ERR_INVAL;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ if (ch == BLADERF_CHANNEL_RX(0)) {
+ shift = BLADERF_XB_RX_SHIFT;
+ } else {
+ shift = BLADERF_XB_TX_SHIFT;
+ }
+
+ *filter = (val >> shift) & 3;
+
+ status = check_xb200_filter(*filter);
+ if (status != 0) {
+ log_debug("Read back invalid GPIO state: 0x%08x\n", val);
+ status = BLADERF_ERR_UNEXPECTED;
+ }
+
+ return status;
+}
+
+static int set_filterbank_mux(struct bladerf *dev, bladerf_channel ch, bladerf_xb200_filter filter)
+{
+ int status;
+ uint32_t orig, val, mask;
+ unsigned int shift;
+ static const char *filters[] = { "50M", "144M", "222M", "custom" };
+
+ assert(filter >= 0);
+ assert(filter < ARRAY_SIZE(filters));
+
+ if (ch == BLADERF_CHANNEL_RX(0)) {
+ mask = BLADERF_XB_RX_MASK;
+ shift = BLADERF_XB_RX_SHIFT;
+ } else {
+ mask = BLADERF_XB_TX_MASK;
+ shift = BLADERF_XB_TX_SHIFT;
+ }
+
+ status = dev->backend->expansion_gpio_read(dev, &orig);
+ if (status != 0) {
+ return status;
+ }
+
+ val = orig & ~mask;
+ val |= filter << shift;
+
+ if (orig != val) {
+ log_debug("Engaging %s band XB-200 %s filter\n", filters[filter],
+ mask == BLADERF_XB_TX_MASK ? "TX" : "RX");
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+ if (status != 0) {
+ return status;
+ }
+ }
+
+
+ return 0;
+}
+
+int xb200_set_filterbank(struct bladerf *dev,
+ bladerf_channel ch,
+ bladerf_xb200_filter filter)
+{
+ struct xb200_xb_data *xb_data = dev->xb_data;
+ uint64_t frequency;
+
+ int status = 0;
+
+ if (ch != BLADERF_CHANNEL_RX(0) && ch != BLADERF_CHANNEL_TX(0)) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ if (NULL == xb_data) {
+ log_error("xb_data is null (do you need to xb200_attach?)\n");
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = check_xb200_filter(filter);
+ if (status != 0) {
+ return status;
+ }
+
+ if (filter == BLADERF_XB200_AUTO_1DB || filter == BLADERF_XB200_AUTO_3DB) {
+ /* Save which soft auto filter mode we're in */
+ xb_data->auto_filter[ch] = filter;
+
+ status = dev->board->get_frequency(dev, ch, &frequency);
+ if (status == 0) {
+ status = xb200_auto_filter_selection(dev, ch, frequency);
+ }
+
+ } else {
+ /* Invalidate the soft auto filter mode entry */
+ xb_data->auto_filter[ch] = -1;
+
+ status = set_filterbank_mux(dev, ch, filter);
+ }
+
+ return status;
+}
+
+int xb200_auto_filter_selection(struct bladerf *dev,
+ bladerf_channel ch,
+ uint64_t frequency)
+{
+ struct xb200_xb_data *xb_data = dev->xb_data;
+ bladerf_xb200_filter filter;
+
+ int status = 0;
+
+ if (frequency >= 300000000u) {
+ return 0;
+ }
+
+ if (ch != BLADERF_CHANNEL_RX(0) && ch != BLADERF_CHANNEL_TX(0)) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ if (NULL == xb_data) {
+ log_error("xb_data is null (do you need to xb200_attach?)\n");
+ return BLADERF_ERR_INVAL;
+ }
+
+ if (xb_data->auto_filter[ch] == BLADERF_XB200_AUTO_1DB) {
+ if (37774405 <= frequency && frequency <= 59535436) {
+ filter = BLADERF_XB200_50M;
+ } else if (128326173 <= frequency && frequency <= 166711171) {
+ filter = BLADERF_XB200_144M;
+ } else if (187593160 <= frequency && frequency <= 245346403) {
+ filter = BLADERF_XB200_222M;
+ } else {
+ filter = BLADERF_XB200_CUSTOM;
+ }
+
+ status = set_filterbank_mux(dev, ch, filter);
+ } else if (xb_data->auto_filter[ch] == BLADERF_XB200_AUTO_3DB) {
+ if (34782924 <= frequency && frequency <= 61899260) {
+ filter = BLADERF_XB200_50M;
+ } else if (121956957 <= frequency && frequency <= 178444099) {
+ filter = BLADERF_XB200_144M;
+ } else if (177522675 <= frequency && frequency <= 260140935) {
+ filter = BLADERF_XB200_222M;
+ } else {
+ filter = BLADERF_XB200_CUSTOM;
+ }
+
+ status = set_filterbank_mux(dev, ch, filter);
+ }
+
+ return status;
+}
+
+#define LMS_RX_SWAP 0x40
+#define LMS_TX_SWAP 0x08
+
+int xb200_set_path(struct bladerf *dev,
+ bladerf_channel ch, bladerf_xb200_path path) {
+ int status;
+ uint32_t val;
+ uint32_t mask;
+ uint8_t lval, lorig = 0;
+
+ if (ch != BLADERF_CHANNEL_RX(0) && ch != BLADERF_CHANNEL_TX(0))
+ return BLADERF_ERR_INVAL;
+
+ status = check_xb200_path(path);
+ if (status != 0) {
+ return status;
+ }
+
+ status = LMS_READ(dev, 0x5A, &lorig);
+ if (status != 0) {
+ return status;
+ }
+
+ lval = lorig;
+
+ if (path == BLADERF_XB200_MIX) {
+ lval |= (ch == BLADERF_CHANNEL_RX(0)) ? LMS_RX_SWAP : LMS_TX_SWAP;
+ } else {
+ lval &= ~((ch == BLADERF_CHANNEL_RX(0)) ? LMS_RX_SWAP : LMS_TX_SWAP);
+ }
+
+ status = LMS_WRITE(dev, 0x5A, lval);
+ if (status != 0) {
+ return status;
+ }
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ if (!(val & BLADERF_XB_RF_ON)) {
+ status = xb200_attach(dev);
+ if (status != 0) {
+ return status;
+ }
+ }
+
+ if (ch == BLADERF_CHANNEL_RX(0)) {
+ mask = (BLADERF_XB_CONFIG_RX_BYPASS_MASK | BLADERF_XB_RX_ENABLE);
+ } else {
+ mask = (BLADERF_XB_CONFIG_TX_BYPASS_MASK | BLADERF_XB_TX_ENABLE);
+ }
+
+ val |= BLADERF_XB_RF_ON;
+ val &= ~mask;
+
+ if (ch == BLADERF_CHANNEL_RX(0)) {
+ if (path == BLADERF_XB200_MIX) {
+ val |= (BLADERF_XB_RX_ENABLE | BLADERF_XB_CONFIG_RX_PATH_MIX);
+ } else {
+ val |= BLADERF_XB_CONFIG_RX_PATH_BYPASS;
+ }
+ } else {
+ if (path == BLADERF_XB200_MIX) {
+ val |= (BLADERF_XB_TX_ENABLE | BLADERF_XB_CONFIG_TX_PATH_MIX);
+ } else {
+ val |= BLADERF_XB_CONFIG_TX_PATH_BYPASS;
+ }
+ }
+
+ return dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+}
+
+int xb200_get_path(struct bladerf *dev,
+ bladerf_channel ch, bladerf_xb200_path *path) {
+ int status;
+ uint32_t val;
+
+ if (ch != BLADERF_CHANNEL_RX(0) && ch != BLADERF_CHANNEL_TX(0))
+ return BLADERF_ERR_INVAL;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ if (ch == BLADERF_CHANNEL_RX(0)) {
+ *path = (val & BLADERF_XB_CONFIG_RX_BYPASS) ?
+ BLADERF_XB200_MIX : BLADERF_XB200_BYPASS;
+
+ } else if (ch == BLADERF_CHANNEL_TX(0)) {
+ *path = (val & BLADERF_XB_CONFIG_TX_BYPASS) ?
+ BLADERF_XB200_MIX : BLADERF_XB200_BYPASS;
+ }
+
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/src/expansion/xb200.h b/Radio/HW/BladeRF/src/expansion/xb200.h
new file mode 100644
index 0000000..3234a7c
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb200.h
@@ -0,0 +1,105 @@
+/**
+ * @file xb.h
+ *
+ * @brief XB-200 support
+ *
+ * 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 EXPANSION_XB200_H_
+#define EXPANSION_XB200_H_
+
+#include <stdbool.h>
+
+#include <libbladeRF.h>
+
+#include "board/board.h"
+
+int xb200_attach(struct bladerf *dev);
+void xb200_detach(struct bladerf *dev);
+int xb200_enable(struct bladerf *dev, bool enable);
+int xb200_init(struct bladerf *dev);
+
+/**
+ * Select an XB-200 filterbank
+ *
+ * @param dev Device handle
+ * @param[in] ch Channel
+ * @param[in] filter XB200 filterbank
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb200_set_filterbank(struct bladerf *dev,
+ bladerf_channel ch,
+ bladerf_xb200_filter filter);
+
+/**
+ * Select an appropriate filterbank, based upon the specified frequency
+ *
+ * @param dev Device handle
+ * @param[in] ch Channel
+ * @param[in] frequency Frequency
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb200_auto_filter_selection(struct bladerf *dev,
+ bladerf_channel ch,
+ uint64_t frequency);
+
+/**
+ * Get the current selected XB-200 filterbank
+ *
+ * @param dev Device handle
+ * @param[in] ch Channel
+ * @param[out] filter Pointer to filterbank, only updated if return value
+ * is 0.
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb200_get_filterbank(struct bladerf *dev,
+ bladerf_channel ch,
+ bladerf_xb200_filter *filter);
+/**
+ * Configure the XB-200 signal path
+ *
+ * @param dev Device handle
+ * @param[in] ch Channel
+ * @param[in] path Desired XB-200 signal path
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb200_set_path(struct bladerf *dev,
+ bladerf_channel ch,
+ bladerf_xb200_path path);
+
+/**
+ * Get the current XB-200 signal path
+ *
+ * @param dev Device handle
+ * @param[in] ch Channel
+ * @param[out] path Pointer to XB200 signal path
+ *
+ * @return 0 on success, value from \ref RETCODES list on failure
+ */
+int xb200_get_path(struct bladerf *dev,
+ bladerf_channel ch,
+ bladerf_xb200_path *path);
+
+#endif
diff --git a/Radio/HW/BladeRF/src/expansion/xb300.c b/Radio/HW/BladeRF/src/expansion/xb300.c
new file mode 100644
index 0000000..15a099d
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb300.c
@@ -0,0 +1,299 @@
+/*
+ * 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
+ */
+
+#include "xb300.h"
+
+#include "log.h"
+
+#define BLADERF_XB_AUX_EN 0x000002
+#define BLADERF_XB_TX_LED 0x000010
+#define BLADERF_XB_RX_LED 0x000020
+#define BLADERF_XB_TRX_TXn 0x000040
+#define BLADERF_XB_TRX_RXn 0x000080
+#define BLADERF_XB_TRX_MASK 0x0000c0
+#define BLADERF_XB_PA_EN 0x000200
+#define BLADERF_XB_LNA_ENn 0x000400
+#define BLADERF_XB_CS 0x010000
+#define BLADERF_XB_CSEL 0x040000
+#define BLADERF_XB_DOUT 0x100000
+#define BLADERF_XB_SCLK 0x400000
+
+int xb300_attach(struct bladerf *dev) {
+ int status;
+ uint32_t val;
+
+ val = BLADERF_XB_TX_LED | BLADERF_XB_RX_LED | BLADERF_XB_TRX_MASK;
+ val |= BLADERF_XB_PA_EN | BLADERF_XB_LNA_ENn;
+ val |= BLADERF_XB_CSEL | BLADERF_XB_SCLK | BLADERF_XB_CS;
+
+ if ((status = dev->backend->expansion_gpio_dir_write(dev, 0xffffffff, val)))
+ return status;
+
+ val = BLADERF_XB_CS | BLADERF_XB_LNA_ENn;
+ if ((status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val)))
+ return status;
+
+ return status;
+}
+
+void xb300_detach(struct bladerf *dev)
+{
+}
+
+int xb300_enable(struct bladerf *dev, bool enable)
+{
+ int status;
+ uint32_t val;
+ float pwr;
+
+ val = BLADERF_XB_CS | BLADERF_XB_CSEL | BLADERF_XB_LNA_ENn;
+ if ((status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val)))
+ return status;
+
+ status = xb300_get_output_power(dev, &pwr);
+
+ return status;
+}
+
+int xb300_init(struct bladerf *dev)
+{
+ int status;
+
+ log_verbose( "Setting TRX path to TX\n" );
+ status = xb300_set_trx(dev, BLADERF_XB300_TRX_TX);
+ if (status != 0) {
+ return status;
+ }
+
+ return 0;
+}
+
+int xb300_set_trx(struct bladerf *dev, bladerf_xb300_trx trx)
+{
+ int status;
+ uint32_t val;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ val &= ~(BLADERF_XB_TRX_MASK);
+
+ switch (trx) {
+ case BLADERF_XB300_TRX_RX:
+ val |= BLADERF_XB_TRX_RXn;
+ break;
+
+ case BLADERF_XB300_TRX_TX:
+ val |= BLADERF_XB_TRX_TXn;
+ break;
+
+ case BLADERF_XB300_TRX_UNSET:
+ break;
+
+ default:
+ log_debug("Invalid TRX option: %d\n", trx);
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+ return status;
+}
+
+int xb300_get_trx(struct bladerf *dev, bladerf_xb300_trx *trx)
+{
+ int status;
+ uint32_t val;
+
+ *trx = BLADERF_XB300_TRX_INVAL;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ val &= BLADERF_XB_TRX_MASK;
+
+ if (!val) {
+ *trx = BLADERF_XB300_TRX_UNSET;
+ } else {
+ *trx = (val & BLADERF_XB_TRX_RXn) ? BLADERF_XB300_TRX_RX : BLADERF_XB300_TRX_TX;
+ }
+
+ /* Sanity check */
+ switch (*trx) {
+ case BLADERF_XB300_TRX_TX:
+ case BLADERF_XB300_TRX_RX:
+ case BLADERF_XB300_TRX_UNSET:
+ break;
+
+ default:
+ log_debug("Read back invalid TRX setting value: %d\n", *trx);
+ status = BLADERF_ERR_INVAL;
+ }
+
+ return status;
+}
+
+int xb300_set_amplifier_enable(struct bladerf *dev,
+ bladerf_xb300_amplifier amp, bool enable) {
+ int status;
+ uint32_t val;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ switch (amp) {
+ case BLADERF_XB300_AMP_PA:
+ if (enable) {
+ val |= BLADERF_XB_TX_LED;
+ val |= BLADERF_XB_PA_EN;
+ } else {
+ val &= ~BLADERF_XB_TX_LED;
+ val &= ~BLADERF_XB_PA_EN;
+ }
+ break;
+
+ case BLADERF_XB300_AMP_LNA:
+ if (enable) {
+ val |= BLADERF_XB_RX_LED;
+ val &= ~BLADERF_XB_LNA_ENn;
+ } else {
+ val &= ~BLADERF_XB_RX_LED;
+ val |= BLADERF_XB_LNA_ENn;
+ }
+ break;
+
+ case BLADERF_XB300_AMP_PA_AUX:
+ if (enable) {
+ val |= BLADERF_XB_AUX_EN;
+ } else {
+ val &= ~BLADERF_XB_AUX_EN;
+ }
+ break;
+
+ default:
+ log_debug("Invalid amplifier selection: %d\n", amp);
+ return BLADERF_ERR_INVAL;
+ }
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+
+ return status;
+}
+
+int xb300_get_amplifier_enable(struct bladerf *dev,
+ bladerf_xb300_amplifier amp, bool *enable)
+{
+ int status;
+ uint32_t val;
+
+ *enable = false;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status != 0) {
+ return status;
+ }
+
+ switch (amp) {
+ case BLADERF_XB300_AMP_PA:
+ *enable = (val & BLADERF_XB_PA_EN);
+ break;
+
+ case BLADERF_XB300_AMP_LNA:
+ *enable = !(val & BLADERF_XB_LNA_ENn);
+ break;
+
+ case BLADERF_XB300_AMP_PA_AUX:
+ *enable = (val & BLADERF_XB_AUX_EN);
+ break;
+
+ default:
+ log_debug("Read back invalid amplifier setting: %d\n", amp);
+ status = BLADERF_ERR_INVAL;
+ }
+
+ return status;
+}
+
+int xb300_get_output_power(struct bladerf *dev, float *pwr)
+{
+ uint32_t val, rval;
+ int i;
+ int ret = 0;
+ int status;
+ float volt, volt2, volt3, volt4;
+
+ status = dev->backend->expansion_gpio_read(dev, &val);
+ if (status) {
+ return status;
+ }
+
+ val &= ~(BLADERF_XB_CS | BLADERF_XB_SCLK | BLADERF_XB_CSEL);
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, BLADERF_XB_SCLK | val);
+ if (status) {
+ return status;
+ }
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, BLADERF_XB_CS | BLADERF_XB_SCLK | val);
+ if (status) {
+ return status;
+ }
+
+ for (i = 1; i <= 14; i++) {
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, val);
+ if (status) {
+ return status;
+ }
+
+ status = dev->backend->expansion_gpio_write(dev, 0xffffffff, BLADERF_XB_SCLK | val);
+ if (status) {
+ return status;
+ }
+
+ status = dev->backend->expansion_gpio_read(dev, &rval);
+ if (status) {
+ return status;
+ }
+
+ if (i >= 2 && i <= 11) {
+ ret |= (!!(rval & BLADERF_XB_DOUT)) << (11 - i);
+ }
+ }
+
+ volt = (1.8f/1024.0f) * ret;
+ volt2 = volt * volt;
+ volt3 = volt2 * volt;
+ volt4 = volt3 * volt;
+
+ *pwr = -503.933f * volt4 +
+ 1409.489f * volt3 -
+ 1487.84f * volt2 +
+ 722.9793f * volt -
+ 114.7529f;
+
+ return 0;
+
+}
diff --git a/Radio/HW/BladeRF/src/expansion/xb300.h b/Radio/HW/BladeRF/src/expansion/xb300.h
new file mode 100644
index 0000000..5fe50de
--- /dev/null
+++ b/Radio/HW/BladeRF/src/expansion/xb300.h
@@ -0,0 +1,94 @@
+/**
+ * @file xb.h
+ *
+ * @brief XB-300 support
+ *
+ * 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 EXPANSION_XB300_H_
+#define EXPANSION_XB300_H_
+
+#include <stdbool.h>
+
+#include <libbladeRF.h>
+
+#include "board/board.h"
+
+int xb300_attach(struct bladerf *dev);
+void xb300_detach(struct bladerf *dev);
+int xb300_enable(struct bladerf *dev, bool enable);
+int xb300_init(struct bladerf *dev);
+
+/**
+ * Configure the XB-300 TRX path
+ *
+ * @param dev Device handle
+ * @param[in] trx Desired XB-300 TRX setting
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb300_set_trx(struct bladerf *dev, bladerf_xb300_trx trx);
+
+/**
+ * Get the current XB-300 signal path
+ *
+ * @param dev Device handle
+ * @param[out] trx XB300 TRX antenna setting
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb300_get_trx(struct bladerf *dev, bladerf_xb300_trx *trx);
+
+/**
+ * Enable or disable selected XB-300 amplifier
+ *
+ * @param dev Device handle
+ * @param[in] amp XB-300 amplifier
+ * @param[in] enable Set true to enable or false to disable
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb300_set_amplifier_enable(struct bladerf *dev,
+ bladerf_xb300_amplifier amp,
+ bool enable);
+/**
+ * Get state of selected XB-300 amplifier
+ *
+ * @param dev Device handle
+ * @param[in] amp XB-300 amplifier
+ * @param[out] enable Set true to enable or false to disable
+ *
+ * @return 0 on success, BLADERF_ERR_* value on failure
+ */
+int xb300_get_amplifier_enable(struct bladerf *dev,
+ bladerf_xb300_amplifier amp,
+ bool *enable);
+/**
+ * Get current PA PDET output power in dBm
+ *
+ * @param dev Device handle
+ * @param[out] val Output power in dBm
+ *
+ * @return 0 on success, value from \ref RETCODES list on failure
+ */
+int xb300_get_output_power(struct bladerf *dev, float *val);
+
+#endif