Hello community,

here is the log from the commit of package soapy-bladerf for openSUSE:Factory 
checked in at 2018-12-14 20:54:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/soapy-bladerf (Old)
 and      /work/SRC/openSUSE:Factory/.soapy-bladerf.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "soapy-bladerf"

Fri Dec 14 20:54:34 2018 rev:2 rq:657888 version:0.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/soapy-bladerf/soapy-bladerf.changes      
2017-11-08 15:09:23.035690355 +0100
+++ /work/SRC/openSUSE:Factory/.soapy-bladerf.new.28833/soapy-bladerf.changes   
2018-12-14 20:56:58.220757579 +0100
@@ -1,0 +2,22 @@
+Thu Dec 13 12:12:22 UTC 2018 - Wojciech Kazubski <w...@ire.pw.edu.pl>
+
+- Update to version 0.4.0
+  * Support for version2 of the libbladerf API
+
+-------------------------------------------------------------------
+Sat Nov 10 13:15:47 UTC 2018 - Wojciech Kazubski <w...@ire.pw.edu.pl>
+
+- Update soapy-module version 0.6 -> 0.7
+
+-------------------------------------------------------------------
+Sat Oct 20 09:54:23 UTC 2018 - Wojciech Kazubski <w...@ire.pw.edu.pl>
+
+- Update to latest 0.3.5 git 20181015
+
+-------------------------------------------------------------------
+Tue Oct  2 22:23:11 UTC 2018 - Wojciech Kazubski <w...@ire.pw.edu.pl>
+
+- Update to latest 0.3.5 git 20180908
+- works with libbladerf ver. 2
+
+-------------------------------------------------------------------

Old:
----
  soapy-bladerf-0.3.3.tar.gz

New:
----
  soapy-bladerf-0.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ soapy-bladerf.spec ++++++
--- /var/tmp/diff_new_pack.C3avHb/_old  2018-12-14 20:56:58.792756869 +0100
+++ /var/tmp/diff_new_pack.C3avHb/_new  2018-12-14 20:56:58.792756869 +0100
@@ -15,11 +15,11 @@
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
-%define soapy_modver 0.6
+%define soapy_modver 0.7
 %define soapy_modname soapysdr%{soapy_modver}-module-bladerf
 
 Name:           soapy-bladerf
-Version:        0.3.3
+Version:        0.4.0
 Release:        0
 Summary:        SoapySDR BladeRF module
 License:        LGPL-2.1
@@ -32,7 +32,6 @@
 BuildRequires:  pkg-config
 BuildRequires:  pkgconfig(SoapySDR)
 BuildRequires:  pkgconfig(libbladeRF)
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
 %description
 Soapy BladeRF - BladeRF device support for Soapy SDR.
@@ -57,8 +56,8 @@
 %cmake_install
 
 %files -n %{soapy_modname}
-%defattr(-,root,root)
-%doc LICENSE.LGPLv2.1 README.md
+%license LICENSE.LGPLv2.1
+%doc Changelog.txt README.md
 %dir %{_libdir}/SoapySDR
 %dir %{_libdir}/SoapySDR/modules%{soapy_modver}
 %{_libdir}/SoapySDR/modules%{soapy_modver}/libbladeRFSupport.so

++++++ soapy-bladerf-0.3.3.tar.gz -> soapy-bladerf-0.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SoapyBladeRF-soapy-bladerf-0.3.3/CMakeLists.txt 
new/SoapyBladeRF-soapy-bladerf-0.4.0/CMakeLists.txt
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/CMakeLists.txt 2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/CMakeLists.txt 2018-12-08 
04:19:47.000000000 +0100
@@ -18,6 +18,18 @@
 message(STATUS "LIBBLADERF_INCLUDE_DIRS - ${LIBBLADERF_INCLUDE_DIRS}")
 message(STATUS "LIBBLADERF_LIBRARIES - ${LIBBLADERF_LIBRARIES}")
 
+#version check for recent bladerf with gain mode API
+message(STATUS "Checking for bladerf_set_gain_mode API...")
+message(STATUS "  Reading ${LIBBLADERF_INCLUDE_DIRS}/libbladeRF.h...")
+file(READ ${LIBBLADERF_INCLUDE_DIRS}/libbladeRF.h libbladeRF_h)
+string(FIND "${libbladeRF_h}" "bladerf_gain_mode" has_bladerf_gain_mode)
+if ("${has_bladerf_gain_mode}" STREQUAL "-1")
+    message(STATUS "  libbladeRF no support for bladerf_set_gain_mode API")
+else()
+    add_definitions(-DHAS_BLADERF_GAIN_MODE)
+    message(STATUS "  libbladeRF supports the bladerf_set_gain_mode API")
+endif()
+
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 include_directories(${LIBBLADERF_INCLUDE_DIRS})
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SoapyBladeRF-soapy-bladerf-0.3.3/Changelog.txt 
new/SoapyBladeRF-soapy-bladerf-0.4.0/Changelog.txt
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/Changelog.txt  2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/Changelog.txt  2018-12-08 
04:19:47.000000000 +0100
@@ -1,3 +1,22 @@
+Release 0.4.0 (2018-12-07)
+==========================
+
+- Support for version2 of the libbladerf API
+
+Release 0.3.5 (2018-03-06)
+==========================
+
+- Added settings hooks for device loading and programming
+- Fixed formatting for setGainMode error message
+- Conditional check for bladerf gain mode support
+
+Release 0.3.4 (2018-01-16)
+==========================
+
+- Support for setting the gain mode (hardware AGC)
+- Support for DC offset and IQ imbalance corrections
+- Added readback support for arbitrary settings API
+
 Release 0.3.3 (2017-04-29)
 ==========================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SoapyBladeRF-soapy-bladerf-0.3.3/README.md 
new/SoapyBladeRF-soapy-bladerf-0.4.0/README.md
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/README.md      2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/README.md      2018-12-08 
04:19:47.000000000 +0100
@@ -1,15 +1,15 @@
 # Soapy SDR plugin for Blade RF
 
-##Build Status
+## Build Status
 
 - Travis: [![Travis Build 
Status](https://travis-ci.org/pothosware/SoapyBladeRF.svg?branch=master)](https://travis-ci.org/pothosware/SoapyBladeRF)
 
-##Dependencies
+## Dependencies
 
 * SoapySDR - https://github.com/pothosware/SoapySDR/wiki
 * LibBladeRF - http://www.github.com/nuand/bladeRF
 
-##Documentation
+## Documentation
 
 * https://github.com/pothosware/SoapyBladeRF/wiki
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_Settings.cpp 
new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_Settings.cpp
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_Settings.cpp   2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_Settings.cpp   2018-12-08 
04:19:47.000000000 +0100
@@ -42,7 +42,11 @@
     _rxBuffSize(0),
     _txBuffSize(0),
     _rxMinTimeoutMs(0),
+    _xb200Mode("disabled"),
+    _samplingMode("internal"),
+    _loopbackMode("disabled"),
     _dev(NULL)
+
 {
     bladerf_devinfo info = devinfo;
     SoapySDR::logf(SOAPY_SDR_INFO, "bladerf_open_with_devinfo()");
@@ -59,8 +63,9 @@
     if (ret == 0) SoapySDR::logf(SOAPY_SDR_INFO, "bladerf_get_serial() = %s", 
serialStr);
 
     //initialize the sample rates to something
-    this->setSampleRate(SOAPY_SDR_RX, 0, 1e6);
-    this->setSampleRate(SOAPY_SDR_TX, 0, 1e6);
+    this->setSampleRate(SOAPY_SDR_RX, 0, 4e6);
+    this->setSampleRate(SOAPY_SDR_TX, 0, 4e6);
+
 }
 
 bladeRF_SoapySDR::~bladeRF_SoapySDR(void)
@@ -72,6 +77,14 @@
 /*******************************************************************
  * Identification API
  ******************************************************************/
+std::string bladeRF_SoapySDR::getHardwareKey(void) const
+{
+    #ifndef LIBBLADERF_V2
+    return "bladeRF";
+    #else
+    return bladerf_get_board_name(_dev);
+    #endif
+}
 
 SoapySDR::Kwargs bladeRF_SoapySDR::getHardwareInfo(void) const
 {
@@ -107,6 +120,24 @@
 }
 
 /*******************************************************************
+ * Channels API
+ ******************************************************************/
+
+size_t bladeRF_SoapySDR::getNumChannels(const int direction) const
+{
+    #ifndef LIBBLADERF_V2
+    return 1;
+    #else
+    return bladerf_get_channel_count(_dev, (direction == 
SOAPY_SDR_RX)?BLADERF_RX:BLADERF_TX);
+    #endif
+}
+
+bool bladeRF_SoapySDR::getFullDuplex(const int, const size_t) const
+{
+    return true;
+}
+
+/*******************************************************************
  * Antenna API
  ******************************************************************/
 
@@ -131,21 +162,223 @@
 }
 
 /*******************************************************************
+ * Calibration API
+ ******************************************************************/
+
+bool bladeRF_SoapySDR::hasDCOffset(const int, const size_t) const
+{
+    return true;
+}
+
+void bladeRF_SoapySDR::setDCOffset(const int direction, const size_t channel, 
const std::complex<double> &offset)
+{
+    int ret = 0;
+    int16_t i = 0;
+    int16_t q = 0;
+
+    if (offset.real() > 1.0)
+        i = int16_t(1.0 * 2048);
+    else
+        i = int16_t(offset.real() * 2048);
+
+    if (offset.imag() > 1.0)
+        q = int16_t(1.0 * 2048);
+    else
+        q = int16_t(offset.imag() * 2048);
+
+    ret = bladerf_set_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_LMS_DCOFF_I, i);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_correction(%f) returned 
%s", i, _err2str(ret).c_str());
+        throw std::runtime_error("setDCOffset() " + _err2str(ret));
+    }
+
+    ret = bladerf_set_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_LMS_DCOFF_Q, q);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_correction(%f) returned 
%s", q, _err2str(ret).c_str());
+        throw std::runtime_error("setDCOffset() " + _err2str(ret));
+    }
+}
+
+std::complex<double> bladeRF_SoapySDR::getDCOffset(const int direction, const 
size_t channel) const
+{
+    int ret = 0;
+    int16_t i = 0;
+    int16_t q = 0;
+
+    ret = bladerf_get_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_LMS_DCOFF_I, &i);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_correction() returned 
%s", _err2str(ret).c_str());
+        throw std::runtime_error("getDCOffset() " + _err2str(ret));
+    }
+
+    ret = bladerf_get_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_LMS_DCOFF_Q, &q);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_correction() returned 
%s", _err2str(ret).c_str());
+        throw std::runtime_error("getDCOffset() " + _err2str(ret));
+    }
+
+    std::complex<double> z(i / 2048.0f, q / 2048.0f);
+    return z;
+}
+
+bool bladeRF_SoapySDR::hasIQBalance(const int, const size_t channel) const
+{
+    return true;
+}
+
+void bladeRF_SoapySDR::setIQBalance(const int direction, const size_t channel, 
const std::complex<double> &balance)
+{
+    int ret = 0;
+    int16_t gain = 0;
+    int16_t phase = 0;
+
+    if (balance.real() > 1.0)
+        gain = int16_t(1.0 * 4096);
+    else
+        gain = int16_t(balance.real() * 4096);
+
+    if (balance.imag() > 1.0)
+        phase = int16_t(1.0 * 4096);
+    else
+        phase = int16_t(balance.imag() * 4096);
+
+    ret = bladerf_set_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_FPGA_GAIN, gain);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_correction(%f) returned 
%s", gain, _err2str(ret).c_str());
+        throw std::runtime_error("setIQBalance() " + _err2str(ret));
+    }
+
+    ret = bladerf_set_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_FPGA_PHASE, phase);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_correction(%f) returned 
%s", phase, _err2str(ret).c_str());
+        throw std::runtime_error("setIQBalance() " + _err2str(ret));
+    }
+}
+
+std::complex<double> bladeRF_SoapySDR::getIQBalance(const int direction, const 
size_t channel) const
+{
+    int ret = 0;
+    int16_t gain = 0;
+    int16_t phase = 0;
+
+    ret = bladerf_get_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_FPGA_GAIN, &gain);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_correction() returned 
%s", _err2str(ret).c_str());
+        throw std::runtime_error("getIQBalance() " + _err2str(ret));
+    }
+
+    ret = bladerf_get_correction(_dev, _toch(direction, channel), 
BLADERF_CORR_FPGA_PHASE, &phase);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_correction() returned 
%s", _err2str(ret).c_str());
+        throw std::runtime_error("getIQBalance() " + _err2str(ret));
+    }
+
+    std::complex<double> z(gain / 4096.0f, phase / 4096.0f);
+    return z;
+}
+
+/*******************************************************************
  * Gain API
  ******************************************************************/
 
-std::vector<std::string> bladeRF_SoapySDR::listGains(const int direction, 
const size_t) const
+bool bladeRF_SoapySDR::hasGainMode(const int direction, const size_t channel) 
const
+{
+    #ifdef HAS_BLADERF_GAIN_MODE
+    #   ifndef LIBBLADERF_V2
+    return _toch(direction, channel) == BLADERF_MODULE_RX ? true : false;
+    #   else
+    return _toch(direction, channel) == BLADERF_CHANNEL_RX(channel) ? true : 
false;
+    #   endif
+    #else
+    return false;
+    #endif
+}
+
+void bladeRF_SoapySDR::setGainMode(const int direction, const size_t channel, 
const bool automatic)
 {
+    #ifdef HAS_BLADERF_GAIN_MODE
+    if (direction == SOAPY_SDR_TX) return; //not supported on tx
+    bladerf_gain_mode gain_mode = automatic ? BLADERF_GAIN_AUTOMATIC : 
BLADERF_GAIN_MANUAL;
+    const int ret = bladerf_set_gain_mode(_dev, _toch(direction, channel), 
gain_mode);
+    if (ret != 0 and automatic) //only throw when mode is automatic, manual is 
default even when call bombs
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_gain_mode(%s) returned 
%s", automatic?"automatic":"manual", _err2str(ret).c_str());
+        throw std::runtime_error("setGainMode() " + _err2str(ret));
+    }
+    #endif
+}
+
+bool bladeRF_SoapySDR::getGainMode(const int direction, const size_t channel) 
const
+{
+    #ifdef HAS_BLADERF_GAIN_MODE
+    if (direction == SOAPY_SDR_TX) return false; //not supported on tx
+    int ret = 0;
+    bladerf_gain_mode gain_mode;
+    bool automatic;
+    ret = bladerf_get_gain_mode(_dev, _toch(direction, channel), &gain_mode);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_gain_mode() returned %s", 
_err2str(ret).c_str());
+        throw std::runtime_error("getGainMode() " + _err2str(ret));
+    }
+
+    automatic = gain_mode == BLADERF_GAIN_AUTOMATIC ? true : false;
+    return automatic;
+    #else
+    return false;
+    #endif
+}
+
+std::vector<std::string> bladeRF_SoapySDR::listGains(const int direction, 
const size_t channel) const
+{
+
     std::vector<std::string> options;
+
+    #ifndef LIBBLADERF_V2
     if (direction == SOAPY_SDR_RX) options.push_back("LNA");
     options.push_back("VGA1");
     options.push_back("VGA2");
+
+    #else
+    // Get board version
+    bladerf_fpga_size variant;
+    const int ret = bladerf_get_fpga_size(_dev, &variant);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_fpga_size(%i) returned 
%s", variant, _err2str(ret).c_str());
+        throw std::runtime_error("listGains() " + _err2str(ret));
+    }
+
+    // BladeRF2
+    if (variant == BLADERF_FPGA_A4 || variant == BLADERF_FPGA_A9)
+    {
+        if (direction == SOAPY_SDR_RX) options.push_back("FULL");
+        else options.push_back("DSA");
+    }
+
+    //BladeRF1
+    else if (variant == BLADERF_FPGA_115KLE || variant == BLADERF_FPGA_40KLE)
+    {
+        if (direction == SOAPY_SDR_RX) options.push_back("LNA");
+        options.push_back("VGA1");
+        options.push_back("VGA2");
+    }
+    #endif
+
     return options;
 }
 
-void bladeRF_SoapySDR::setGain(const int direction, const size_t, const double 
value)
+void bladeRF_SoapySDR::setGain(const int direction, const size_t channel, 
const double value)
 {
-    const int ret = bladerf_set_gain(_dev, _dir2mod(direction), int(value));
+    const int ret = bladerf_set_gain(_dev, _toch(direction, channel), 
int(value));
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_gain(%f) returned %s", 
value, _err2str(ret).c_str());
@@ -153,9 +386,15 @@
     }
 }
 
-void bladeRF_SoapySDR::setGain(const int direction, const size_t, const 
std::string &name, const double value)
+void bladeRF_SoapySDR::setGain(const int direction, const size_t channel, 
const std::string &name, const double value)
 {
+    // Note: The BladeRF folks do not recommend using this API anymore.
+    // It may be unavailable or have unintended behavior if AGC is turned on.
+
     int ret = 0;
+
+    #ifndef LIBBLADERF_V2
+    // Compatibility for bladerf1
     if (direction == SOAPY_SDR_RX and name == "LNA")
     {
         if      (value < 1.5) ret = bladerf_set_lna_gain(_dev, 
BLADERF_LNA_GAIN_BYPASS);
@@ -166,17 +405,75 @@
     else if (direction == SOAPY_SDR_RX and name == "VGA2") ret = 
bladerf_set_rxvga2(_dev, int(value));
     else if (direction == SOAPY_SDR_TX and name == "VGA1") ret = 
bladerf_set_txvga1(_dev, int(value));
     else if (direction == SOAPY_SDR_TX and name == "VGA2") ret = 
bladerf_set_txvga2(_dev, int(value));
+
     else throw std::runtime_error("setGain("+name+") -- unknown name");
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_vga(%f) returned %s", 
value, _err2str(ret).c_str());
         throw std::runtime_error("setGain("+name+") " + _err2str(ret));
     }
+
+    #else
+    bladerf_gain _value = (bladerf_gain)value;
+    bladerf_channel _channel = _toch(direction, channel);
+    bladerf_fpga_size variant;
+    ret = bladerf_get_fpga_size(_dev, &variant);
+
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_fpga_size(%i) returned 
%s", variant, _err2str(ret).c_str());
+        throw std::runtime_error("setGain() " + _err2str(ret));
+    }
+
+    // BladeRF1 Support
+    if (variant == BLADERF_FPGA_115KLE or variant == BLADERF_FPGA_40KLE)
+    {
+        if (direction == SOAPY_SDR_RX and name == "LNA")
+        {
+            if      (value < 1.5) ret = bladerf_set_gain_stage(_dev, _channel, 
"lna", BLADERF_LNA_GAIN_BYPASS);
+            else if (value < 4.5) ret = bladerf_set_gain_stage(_dev, _channel, 
"lna", BLADERF_LNA_GAIN_MID);
+            else                  ret = bladerf_set_gain_stage(_dev, _channel, 
"lna", BLADERF_LNA_GAIN_MAX);
+        }
+        else if (direction == SOAPY_SDR_RX and name == "VGA1") ret = 
bladerf_set_gain_stage(_dev, _channel, "rxvga1", _value);
+        else if (direction == SOAPY_SDR_RX and name == "VGA2") ret = 
bladerf_set_gain_stage(_dev, _channel, "rxvga2", _value);
+        else if (direction == SOAPY_SDR_TX and name == "VGA1") ret = 
bladerf_set_gain_stage(_dev, _channel, "txvga1", _value);
+        else if (direction == SOAPY_SDR_TX and name == "VGA2") ret = 
bladerf_set_gain_stage(_dev, _channel, "txvga2", _value);
+        else throw std::runtime_error("setGain("+name+") -- unknown name");
+    }
+
+    // BladeRF2 Support
+    else if (variant == BLADERF_FPGA_A4 or variant == BLADERF_FPGA_A9)
+    {
+        if      (direction == SOAPY_SDR_RX and name == "FULL") ret = 
bladerf_set_gain_stage(_dev, _channel, "full", _value);
+        else if (direction == SOAPY_SDR_TX and name == "DSA")  ret = 
bladerf_set_gain_stage(_dev, _channel, "dsa", _value);
+        else throw std::runtime_error("setGain("+name+") -- unknown name");
+    }
+    else throw std::runtime_error("setGain("+name+") -- unknown board type");
+
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_gain_stage(%f) returned 
%s", value, _err2str(ret).c_str());
+        throw std::runtime_error("setGain("+name+") " + _err2str(ret));
+    }
+    #endif
 }
 
-double bladeRF_SoapySDR::getGain(const int direction, const size_t, const 
std::string &name) const
+double bladeRF_SoapySDR::getGain(const int direction, const size_t channel) 
const
+{
+    bladerf_gain gain;
+    const int ret = bladerf_get_gain(_dev, _toch(direction, channel), &gain);
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_gain(%zu) returned %s", 
channel, _err2str(ret).c_str());
+        throw std::runtime_error("getGain() " + _err2str(ret));
+    }
+    return (double)gain;
+}
+
+double bladeRF_SoapySDR::getGain(const int direction, const size_t channel, 
const std::string &name) const
 {
     int ret = 0;
+    #ifndef LIBBLADERF_V2
     int gain = 0;
     if (direction == SOAPY_SDR_RX and name == "LNA")
     {
@@ -195,34 +492,124 @@
     else if (direction == SOAPY_SDR_TX and name == "VGA1") ret = 
bladerf_get_txvga1(_dev, &gain);
     else if (direction == SOAPY_SDR_TX and name == "VGA2") ret = 
bladerf_get_txvga2(_dev, &gain);
     else throw std::runtime_error("getGain("+name+") -- unknown name");
+    #else
+
+    bladerf_gain gain;
+    bladerf_channel _channel = _toch(direction, channel);
+    bladerf_fpga_size variant;
+    ret = bladerf_get_fpga_size(_dev, &variant);
+
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_fpga_size(%i) returned 
%s", variant, _err2str(ret).c_str());
+        throw std::runtime_error("setGain() " + _err2str(ret));
+    }
+
+    // BladeRF1 Support
+    if (variant == BLADERF_FPGA_115KLE or variant == BLADERF_FPGA_40KLE)
+    {
+
+        if (direction == SOAPY_SDR_RX and name == "LNA")
+        {
+            ret = bladerf_get_gain_stage(_dev, channel, "lna", &gain);
+            switch (gain)
+            {
+            case BLADERF_LNA_GAIN_UNKNOWN: gain = 0; break;
+            case BLADERF_LNA_GAIN_BYPASS: gain = 0; break;
+            case BLADERF_LNA_GAIN_MID: gain = BLADERF_LNA_GAIN_MID_DB; break;
+            case BLADERF_LNA_GAIN_MAX: gain = BLADERF_LNA_GAIN_MAX_DB; break;
+            }
+        }
+        else if (direction == SOAPY_SDR_RX and name == "VGA1") ret = 
bladerf_get_gain_stage(_dev, channel, "rxvga1", &gain);
+        else if (direction == SOAPY_SDR_RX and name == "VGA2") ret = 
bladerf_get_gain_stage(_dev, channel, "rxvga2", &gain);
+        else if (direction == SOAPY_SDR_TX and name == "VGA1") ret = 
bladerf_get_gain_stage(_dev, channel, "txvga1", &gain);
+        else if (direction == SOAPY_SDR_TX and name == "VGA2") ret = 
bladerf_get_gain_stage(_dev, channel, "txvga2", &gain);
+        else throw std::runtime_error("getGain("+name+") -- unknown name");
+    }
+
+    // BladeRF2 Support
+    else if (variant == BLADERF_FPGA_A4 or variant == BLADERF_FPGA_A9)
+    {
+        if      (direction == SOAPY_SDR_RX and name == "FULL") ret = 
bladerf_get_gain_stage(_dev, _channel, "full", &gain);
+        else if (direction == SOAPY_SDR_TX and name == "DSA")  ret = 
bladerf_get_gain_stage(_dev, _channel, "dsa", &gain);
+        else throw std::runtime_error("setGain("+name+") -- unknown name");
+    }
+    else throw std::runtime_error("setGain("+name+") -- unknown board type");
+    gain = (double)gain;
+
+    #endif
+
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_vga() returned %s", 
_err2str(ret).c_str());
         throw std::runtime_error("getGain("+name+") " + _err2str(ret));
     }
+
     return gain;
 }
 
-SoapySDR::Range bladeRF_SoapySDR::getGainRange(const int direction, const 
size_t, const std::string &name) const
+SoapySDR::Range bladeRF_SoapySDR::getGainRange(const int direction, const 
size_t channel, const std::string &name) const
 {
+    #ifndef LIBBLADERF_V2
     if (direction == SOAPY_SDR_RX and name == "LNA")  return 
SoapySDR::Range(0, BLADERF_LNA_GAIN_MAX_DB);
     if (direction == SOAPY_SDR_RX and name == "VGA1") return 
SoapySDR::Range(BLADERF_RXVGA1_GAIN_MIN, BLADERF_RXVGA1_GAIN_MAX);
     if (direction == SOAPY_SDR_RX and name == "VGA2") return 
SoapySDR::Range(BLADERF_RXVGA2_GAIN_MIN, BLADERF_RXVGA2_GAIN_MAX);
     if (direction == SOAPY_SDR_TX and name == "VGA1") return 
SoapySDR::Range(BLADERF_TXVGA1_GAIN_MIN, BLADERF_TXVGA1_GAIN_MAX);
     if (direction == SOAPY_SDR_TX and name == "VGA2") return 
SoapySDR::Range(BLADERF_TXVGA2_GAIN_MIN, BLADERF_TXVGA2_GAIN_MAX);
     else throw std::runtime_error("getGainRange("+name+") -- unknown name");
+    #else
+
+    const bladerf_range* range;
+    bladerf_fpga_size variant;
+    const char* stage;
+    int ret = 0;
+
+    ret = bladerf_get_fpga_size(_dev, &variant);
+
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_fpga_size(%i) returned 
%s", variant, _err2str(ret).c_str());
+        throw std::runtime_error("getGainRange() " + _err2str(ret));
+    }
+
+    if (variant == BLADERF_FPGA_115KLE or variant == BLADERF_FPGA_40KLE)
+    {
+        if      (direction == SOAPY_SDR_RX and name == "LNA") stage = "lna";
+        else if (direction == SOAPY_SDR_RX and name == "VGA1") stage = 
"rxvga1";
+        else if (direction == SOAPY_SDR_RX and name == "VGA2") stage = 
"rxvga2";
+        else if (direction == SOAPY_SDR_TX and name == "VGA1") stage = 
"txvga1";
+        else if (direction == SOAPY_SDR_TX and name == "VGA2") stage = 
"txvga2";
+        else throw std::runtime_error("getGainRange("+name+") -- unknown 
name");
+    }
+    else if (variant == BLADERF_FPGA_A4 or variant == BLADERF_FPGA_A9)
+    {
+        if      (direction == SOAPY_SDR_RX and name == "FULL") stage = "full";
+        else if (direction == SOAPY_SDR_TX and name == "DSA") stage = "dsa";
+        else throw std::runtime_error("getGainRange("+name+") -- unknown 
name");
+    }
+    else throw std::runtime_error("getGainRange() board not supported");
+
+    ret = bladerf_get_gain_stage_range(_dev, _toch(direction, channel), stage, 
&range);
+
+    if (ret != 0)
+    {
+        SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_gain_stage_range(%s) 
returned %s", stage, _err2str(ret).c_str());
+        throw std::runtime_error("getGainRange()" + _err2str(ret));
+    }
+    return SoapySDR::Range(range->min, range->max);
+    #endif
 }
 
 /*******************************************************************
  * Frequency API
  ******************************************************************/
 
-void bladeRF_SoapySDR::setFrequency(const int direction, const size_t, const 
std::string &name, const double frequency, const SoapySDR::Kwargs &)
+void bladeRF_SoapySDR::setFrequency(const int direction, const size_t channel, 
const std::string &name, const double frequency, const SoapySDR::Kwargs &)
 {
     if (name == "BB") return; //for compatibility
     if (name != "RF") throw std::runtime_error("setFrequency("+name+") unknown 
name");
 
-    int ret = bladerf_set_frequency(_dev, _dir2mod(direction), (unsigned 
int)(frequency));
+    int ret = bladerf_set_frequency(_dev, _toch(direction, channel), (unsigned 
int)(frequency));
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_frequency(%f) returned 
%s", frequency, _err2str(ret).c_str());
@@ -230,13 +617,13 @@
     }
 }
 
-double bladeRF_SoapySDR::getFrequency(const int direction, const size_t, const 
std::string &name) const
+double bladeRF_SoapySDR::getFrequency(const int direction, const size_t 
channel, const std::string &name) const
 {
     if (name == "BB") return 0.0; //for compatibility
     if (name != "RF") throw std::runtime_error("getFrequency("+name+") unknown 
name");
 
-    unsigned int freq = 0;
-    int ret = bladerf_get_frequency(_dev, _dir2mod(direction), &freq);
+    bladerf_frequency freq = 0;
+    int ret = bladerf_get_frequency(_dev, _toch(direction, channel), &freq);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_frequency() returned %s", 
_err2str(ret).c_str());
@@ -245,14 +632,14 @@
     return freq;
 }
 
-std::vector<std::string> bladeRF_SoapySDR::listFrequencies(const int, const 
size_t) const
+std::vector<std::string> bladeRF_SoapySDR::listFrequencies(const int, const 
size_t channel) const
 {
     std::vector<std::string> components;
     components.push_back("RF");
     return components;
 }
 
-SoapySDR::RangeList bladeRF_SoapySDR::getFrequencyRange(const int, const 
size_t, const std::string &name) const
+SoapySDR::RangeList bladeRF_SoapySDR::getFrequencyRange(const int, const 
size_t channel, const std::string &name) const
 {
     if (name == "BB") return SoapySDR::RangeList(1, SoapySDR::Range(0.0, 
0.0)); //for compatibility
     if (name != "RF") throw std::runtime_error("getFrequencyRange("+name+") 
unknown name");
@@ -276,7 +663,7 @@
     //stash the approximate hardware time so it can be restored
     const long long timeNow = this->getHardwareTime();
 
-    int ret = bladerf_set_rational_sample_rate(_dev, _dir2mod(direction), 
&ratRate, NULL);
+    int ret = bladerf_set_rational_sample_rate(_dev, _toch(direction, 
channel), &ratRate, NULL);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_rational_sample_rate(%f) 
returned %s", rate, _err2str(ret).c_str());
@@ -301,10 +688,10 @@
     SoapySDR::logf(SOAPY_SDR_INFO, "setSampleRate(%d, %f MHz), actual = %f 
MHz", direction, rate/1e6, actual/1e6);
 }
 
-double bladeRF_SoapySDR::getSampleRate(const int direction, const size_t) const
+double bladeRF_SoapySDR::getSampleRate(const int direction, const size_t 
channel) const
 {
     bladerf_rational_rate ratRate;
-    int ret = bladerf_get_rational_sample_rate(_dev, _dir2mod(direction), 
&ratRate);
+    int ret = bladerf_get_rational_sample_rate(_dev, _toch(direction, 
channel), &ratRate);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_rational_sample_rate() 
returned %s", _err2str(ret).c_str());
@@ -314,7 +701,7 @@
     return double(ratRate.integer) + (double(ratRate.num)/double(ratRate.den));
 }
 
-std::vector<double> bladeRF_SoapySDR::listSampleRates(const int, const size_t) 
const
+std::vector<double> bladeRF_SoapySDR::listSampleRates(const int, const size_t 
channel) const
 {
     std::vector<double> options;
     for (double r = 160e3; r <= 200e3; r += 40e3) options.push_back(r);
@@ -325,18 +712,18 @@
     return options;
 }
 
-void bladeRF_SoapySDR::setBandwidth(const int direction, const size_t, const 
double bw)
+void bladeRF_SoapySDR::setBandwidth(const int direction, const size_t channel, 
const double bw)
 {
     //bypass the filter when sufficiently large BW is selected
     if (bw > BLADERF_BANDWIDTH_MAX)
     {
-        bladerf_set_lpf_mode(_dev, _dir2mod(direction), BLADERF_LPF_BYPASSED);
+        bladerf_set_lpf_mode(_dev, _toch(direction, channel), 
BLADERF_LPF_BYPASSED);
         return;
     }
 
     //otherwise set to normal and configure the filter bandwidth
-    bladerf_set_lpf_mode(_dev, _dir2mod(direction), BLADERF_LPF_NORMAL);
-    int ret = bladerf_set_bandwidth(_dev, _dir2mod(direction), (unsigned 
int)(bw), NULL);
+    bladerf_set_lpf_mode(_dev, _toch(direction, channel), BLADERF_LPF_NORMAL);
+    int ret = bladerf_set_bandwidth(_dev, _toch(direction, channel), (unsigned 
int)(bw), NULL);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_set_bandwidth(%f) returned 
%s", bw, _err2str(ret).c_str());
@@ -344,10 +731,10 @@
     }
 }
 
-double bladeRF_SoapySDR::getBandwidth(const int direction, const size_t) const
+double bladeRF_SoapySDR::getBandwidth(const int direction, const size_t 
channel) const
 {
     unsigned int bw = 0;
-    int ret = bladerf_get_bandwidth(_dev, _dir2mod(direction), &bw);
+    int ret = bladerf_get_bandwidth(_dev, _toch(direction, channel), &bw);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_get_bandwidth() returned %s", 
_err2str(ret).c_str());
@@ -395,7 +782,11 @@
 {
     if (not what.empty()) return SoapySDR::Device::getHardwareTime(what);
     uint64_t ticksNow = 0;
+    #ifndef LIBBLADERF_V2
     const int ret = bladerf_get_timestamp(_dev, BLADERF_MODULE_RX, &ticksNow);
+    #else
+    const int ret = bladerf_get_timestamp(_dev, BLADERF_RX, &ticksNow);
+    #endif
 
     if (ret != 0)
     {
@@ -463,6 +854,8 @@
 {
     SoapySDR::ArgInfoList setArgs;
 
+    const bool isBladeRF1 = this->getNumChannels(SOAPY_SDR_RX) == 1;
+
     // XB200 setting
     SoapySDR::ArgInfo xb200SettingArg;
     xb200SettingArg.key = "xb200";
@@ -487,7 +880,7 @@
     xb200SettingArg.options.push_back("custom");
     xb200SettingArg.optionNames.push_back("Filterbank: Custom");
 
-    setArgs.push_back(xb200SettingArg);
+    if (isBladeRF1) setArgs.push_back(xb200SettingArg);
 
     // Sampling mode
     SoapySDR::ArgInfo samplingModeArg;
@@ -501,9 +894,10 @@
     samplingModeArg.options.push_back("external");
     samplingModeArg.optionNames.push_back("Direct Sampling");
 
-    setArgs.push_back(samplingModeArg);
+    if (isBladeRF1) setArgs.push_back(samplingModeArg);
 
     // Loopback
+    #ifndef LIBBLADERF_V2
     SoapySDR::ArgInfo lookbackArg;
     lookbackArg.key = "loopback";
     lookbackArg.value = "disabled";
@@ -528,21 +922,147 @@
     lookbackArg.optionNames.push_back("RF: TXMIX to LNA2");
     lookbackArg.options.push_back("rf_lna3");
     lookbackArg.optionNames.push_back("RF: TXMIX to LNA3");
+    #else
+    SoapySDR::ArgInfo lookbackArg;
+    lookbackArg.key = "loopback";
+    lookbackArg.name = "Loopback Mode";
+    lookbackArg.description = "Enable/disable internal loopback";
+    lookbackArg.type = SoapySDR::ArgInfo::STRING;
+    const bladerf_loopback_modes *modes(nullptr);
+    const int numModes = bladerf_get_loopback_modes(_dev, &modes);
+    if (modes and numModes > 0) for (int i = 0; i < numModes; i++)
+    {
+        if (modes[i].mode == BLADERF_LB_NONE) lookbackArg.value = 
modes[i].name;
+        lookbackArg.options.push_back(modes[i].name);
+    }
+    #endif
 
     setArgs.push_back(lookbackArg);
 
+    // Device reset
+    SoapySDR::ArgInfo resetArg;
+    resetArg.key = "reset";
+    resetArg.value = "false";
+    resetArg.name = "Reset Device";
+    resetArg.description = "Reset the device, causing it to reload its 
firmware from flash.";
+    resetArg.type = SoapySDR::ArgInfo::BOOL;
+    resetArg.options.push_back("true");
+    resetArg.optionNames.push_back("True");
+    resetArg.options.push_back("false");
+    resetArg.optionNames.push_back("False");
+
+    setArgs.push_back(resetArg);
+
+    // Erase stored FPGA
+    SoapySDR::ArgInfo eraseArg;
+    eraseArg.key = "erase_stored_fpga";
+    eraseArg.value = "false";
+    eraseArg.name = "Erase the FPGA region of flash";
+    eraseArg.description = "Erase the FPGA region of SPI flash, effectively 
disabling FPGA autoloading.";
+    eraseArg.type = SoapySDR::ArgInfo::BOOL;
+    eraseArg.options.push_back("true");
+    eraseArg.optionNames.push_back("True");
+    eraseArg.options.push_back("false");
+    eraseArg.optionNames.push_back("False");
+
+    setArgs.push_back(eraseArg);
+
+    // Flash firmware
+    SoapySDR::ArgInfo firmwareArg;
+    firmwareArg.key = "flash_firmware";
+    firmwareArg.value = "";
+    firmwareArg.name = "Write FX3 firmware to flash";
+    firmwareArg.description = "Write FX3 firmware to the bladeRF's SPI flash 
from the provided file path. This will require a power cycle to take effect.";
+    firmwareArg.type = SoapySDR::ArgInfo::STRING;
+
+    setArgs.push_back(firmwareArg);
+
+    // Flash FPGA
+    SoapySDR::ArgInfo flashArg;
+    flashArg.key = "flash_fpga";
+    flashArg.value = "";
+    flashArg.name = "Write to the FPGA region of flash";
+    flashArg.description = "Write FPGA image to the bladeRF's SPI flash from 
the provided file path and enable FPGA loading from SPI flash at power on.";
+    flashArg.type = SoapySDR::ArgInfo::STRING;
+
+    setArgs.push_back(flashArg);
+
+    // Jump to bootloader
+    SoapySDR::ArgInfo bootloaderArg;
+    bootloaderArg.key = "jump_to_bootloader";
+    bootloaderArg.value = "false";
+    bootloaderArg.name = "Clear out a firmware signature word in flash and 
jump to FX3 bootloader";
+    bootloaderArg.description = "The device will continue to boot into the FX3 
bootloader across power cycles until new firmware is written to the device.";
+    bootloaderArg.type = SoapySDR::ArgInfo::BOOL;
+    bootloaderArg.options.push_back("true");
+    bootloaderArg.optionNames.push_back("True");
+    bootloaderArg.options.push_back("false");
+    bootloaderArg.optionNames.push_back("False");
+
+    setArgs.push_back(bootloaderArg);
+
+    // Load FPGA
+    SoapySDR::ArgInfo loadArg;
+    loadArg.key = "load_fpga";
+    loadArg.value = "";
+    loadArg.name = "Load device's FPGA";
+    loadArg.description = "Load device's FPGA from the provided file path. 
Note that this FPGA configuration will be reset at the next power cycle.";
+    loadArg.type = SoapySDR::ArgInfo::STRING;
+
+    setArgs.push_back(loadArg);
+
     return setArgs;
 }
 
+std::string bladeRF_SoapySDR::readSetting(const std::string &key) const
+{
+    if (key == "xb200") {
+        return _xb200Mode;
+    } else if (key == "sampling_mode") {
+        return _samplingMode;
+    } else if (key == "loopback") {
+        #ifndef LIBBLADERF_V2
+        return _loopbackMode;
+        #else
+        bladerf_loopback lb;
+        bladerf_get_loopback(_dev, &lb);
+        const bladerf_loopback_modes *modes(nullptr);
+        const int numModes = bladerf_get_loopback_modes(_dev, &modes);
+        if (modes and numModes > 0) for (int i = 0; i < numModes; i++)
+        {
+            if (modes[i].mode == lb) return modes[i].name;
+        }
+        return "unknown";
+        #endif
+    } else if (key == "reset") {
+        return "false";
+    } else if (key == "erase_stored_fpga") {
+        return "false";
+    } else if (key == "flash_firmware") {
+        return "";
+    } else if (key == "flash_fpga") {
+        return "";
+    } else if (key == "jump_to_bootloader") {
+        return "false";
+    } else if (key == "load_fpga") {
+        return "";
+    }
+
+    SoapySDR_logf(SOAPY_SDR_WARNING, "Unknown setting '%s'", key.c_str());
+    return "";
+}
+
 void bladeRF_SoapySDR::writeSetting(const std::string &key, const std::string 
&value)
 {
     if (key == "xb200")
     {
+        #ifndef LIBBLADERF_V2
         // Verify that a valid setting has arrived
         std::vector<std::string> xb200_validSettings{ "disabled", "50M", 
"144M", "222M", "auto1db", "auto3db", "auto", "custom" };
         if (std::find(std::begin(xb200_validSettings), 
std::end(xb200_validSettings), value) != std::end(xb200_validSettings))
         {
             // --> Valid setting has arrived
+            _xb200Mode = value;
 
             // Get attached expansion device
             bladerf_xb _bladerf_xb_attached = bladerf_xb::BLADERF_XB_NONE;
@@ -644,6 +1164,7 @@
             SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: Invalid XB200 setting 
'%s'", value.c_str());
             //throw std::runtime_error("writeSetting(" + key + "," + value + 
") unknown value");
         }
+        #endif
     }
     else if (key == "sampling_mode")
     {
@@ -657,6 +1178,7 @@
         if (std::find(std::begin(sampling_mode_validSettings), 
std::end(sampling_mode_validSettings), value) != 
std::end(sampling_mode_validSettings))
         {
             // --> Valid setting has arrived
+            _samplingMode = value;
 
             // Set the sampling mode
             int ret = 0;
@@ -687,11 +1209,13 @@
     }
     else if (key == "loopback")
     {
+        #ifndef LIBBLADERF_V2
         // Verify that a valid setting has arrived
         std::vector<std::string> loopback_validSettings{ "disabled", 
"firmware", "bb_txlpf_rxvga2", "bb_txvga1_rxvga2", "bb_txlpf_rxlpf", 
"bb_txvga1_rxlpf", "rf_lna1", "rf_lna2", "rf_lna3" };
         if (std::find(std::begin(loopback_validSettings), 
std::end(loopback_validSettings), value) != std::end(loopback_validSettings))
         {
             // --> Valid setting has arrived
+            _loopbackMode = value;
 
             // Which loopback mode was selected?
             bladerf_loopback loopback = bladerf_loopback::BLADERF_LB_NONE;
@@ -742,6 +1266,17 @@
                 // Disables loopback and returns to normal operation
                 loopback = bladerf_loopback::BLADERF_LB_NONE;
             }
+        #else
+        bladerf_loopback loopback(BLADERF_LB_NONE);
+        const bladerf_loopback_modes *modes(nullptr);
+        const int numModes = bladerf_get_loopback_modes(_dev, &modes);
+        if (modes and numModes > 0) for (int i = 0; i < numModes; i++)
+        {
+            if (modes[i].name == value) loopback = modes[i].mode;
+        }
+        if (bladerf_is_loopback_mode_supported(_dev, loopback))
+        {
+        #endif
 
             // If the loopback isn't already set, set the loopback
             bladerf_loopback _bladerf_loopback = 
bladerf_loopback::BLADERF_LB_NONE;
@@ -764,6 +1299,105 @@
             //throw std::runtime_error("writeSetting(" + key + "," + value + 
") unknown value");
         }
     }
+    else if (key == "reset")
+    {
+        // Verify that a valid setting has arrived
+        if (value == "true") {
+            // --> Valid setting has arrived
+            int ret = bladerf_device_reset(_dev);
+            if (ret != 0)
+            {
+                SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_device_reset(%s) 
returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: Invalid reset setting 
'%s'", value.c_str());
+        }*/
+    }
+    else if (key == "erase_stored_fpga")
+    {
+        // Verify that a valid setting has arrived
+        if (value == "true") {
+            // --> Valid setting has arrived
+            int ret = bladerf_erase_stored_fpga(_dev);
+            if (ret != 0)
+            {
+                SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_erase_stored_fpga(%s) 
returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: Invalid erase setting 
'%s'", value.c_str());
+        }*/
+    }
+    else if (key == "flash_firmware")
+    {
+        if (!value.empty()) {
+            int ret = bladerf_flash_firmware(_dev, value.c_str());
+            if (ret != 0) {
+                SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_flash_firmware(%s) 
returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: The provided firmware 
file path is empty");
+        }*/
+    }
+    else if (key == "flash_fpga")
+    {
+        if (!value.empty()) {
+            int ret = bladerf_flash_fpga(_dev, value.c_str());
+            if (ret != 0) {
+                SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_flash_fpga(%s) 
returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: The provided FPGA image 
path is empty");
+        }*/
+    }
+    else if (key == "jump_to_bootloader")
+    {
+        // Verify that a valid setting has arrived
+        if (value == "true") {
+            // --> Valid setting has arrived
+            int ret = bladerf_jump_to_bootloader(_dev);
+            if (ret != 0)
+            {
+                SoapySDR::logf(SOAPY_SDR_ERROR, 
"bladerf_jump_to_bootloader(%s) returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: Invalid jump to 
bootloader setting '%s'", value.c_str());
+        }*/
+    }
+    else if (key == "load_fpga")
+    {
+        if (!value.empty()) {
+            int ret = bladerf_load_fpga(_dev, value.c_str());
+            if (ret != 0) {
+                SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_load_fpga(%s) 
returned %s", value.c_str(),
+                               _err2str(ret).c_str());
+                throw std::runtime_error("writeSetting() " + _err2str(ret));
+            }
+        }
+        /*else {
+            // --> Invalid setting has arrived
+            SoapySDR::logf(SOAPY_SDR_ERROR, "bladeRF: The provided FPGA image 
path is empty");
+        }*/
+    }
     else
     {
         throw std::runtime_error("writeSetting(" + key + ") unknown setting");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_SoapySDR.hpp 
new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_SoapySDR.hpp
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_SoapySDR.hpp   2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_SoapySDR.hpp   2018-12-08 
04:19:47.000000000 +0100
@@ -27,6 +27,14 @@
 #include <cstdio>
 #include <queue>
 
+#if defined(LIBBLADERF_API_VERSION) && (LIBBLADERF_API_VERSION >= 0x02000000)
+#define LIBBLADERF_V2
+#endif
+
+#ifndef LIBBLADERF_V2
+typedef unsigned int bladerf_frequency;
+#endif
+
 /*!
  * Storage for rx commands and tx responses
  */
@@ -61,10 +69,7 @@
         return "bladeRF";
     }
 
-    std::string getHardwareKey(void) const
-    {
-        return "bladeRF";
-    }
+    std::string getHardwareKey(void) const;
 
     SoapySDR::Kwargs getHardwareInfo(void) const;
 
@@ -72,15 +77,9 @@
      * Channels API
      ******************************************************************/
 
-    size_t getNumChannels(const int) const
-    {
-        return 1;
-    }
+    size_t getNumChannels(const int) const;
 
-    bool getFullDuplex(const int, const size_t) const
-    {
-        return true;
-    }
+    bool getFullDuplex(const int, const size_t) const;
 
     /*******************************************************************
      * Stream API
@@ -147,15 +146,39 @@
     std::string getAntenna(const int direction, const size_t channel) const;
 
     /*******************************************************************
+     * Calibration API
+     ******************************************************************/
+
+    bool hasDCOffset(const int direction, const size_t) const;
+
+    void setDCOffset(const int direction, const size_t, const 
std::complex<double> &offset);
+
+    std::complex<double> getDCOffset(const int direction, const size_t) const;
+
+    bool hasIQBalance(const int direction, const size_t) const;
+
+    void setIQBalance(const int direction, const size_t, const 
std::complex<double> &balance);
+
+    std::complex<double> getIQBalance(const int direction, const size_t) const;
+
+    /*******************************************************************
      * Gain API
      ******************************************************************/
 
+    bool hasGainMode(const int direction, const size_t channel) const;
+
+    void setGainMode(const int direction, const size_t channel, const bool 
automatic);
+
+    bool getGainMode(const int direction, const size_t channel) const;
+
     std::vector<std::string> listGains(const int direction, const size_t 
channel) const;
 
     void setGain(const int direction, const size_t channel, const double 
value);
 
     void setGain(const int direction, const size_t channel, const std::string 
&name, const double value);
 
+    double getGain(const int direction, const size_t channel) const;
+
     double getGain(const int direction, const size_t channel, const 
std::string &name) const;
 
     SoapySDR::Range getGainRange(const int direction, const size_t channel, 
const std::string &name) const;
@@ -214,6 +237,8 @@
 
     void writeSetting(const std::string &key, const std::string &value);
 
+    std::string readSetting(const std::string &key) const;
+
     /*******************************************************************
      * GPIO API
      ******************************************************************/
@@ -234,10 +259,17 @@
 
 private:
 
-    static bladerf_module _dir2mod(const int direction)
+    #ifndef LIBBLADERF_V2
+    static bladerf_module _toch(const int direction, const size_t)
     {
         return (direction == SOAPY_SDR_RX)?BLADERF_MODULE_RX:BLADERF_MODULE_TX;
     }
+    #else
+    static bladerf_channel _toch(const int direction, const size_t channel)
+    {
+        return (direction == 
SOAPY_SDR_RX)?BLADERF_CHANNEL_RX(channel):BLADERF_CHANNEL_TX(channel);
+    }
+    #endif
 
     static std::string _err2str(const int err)
     {
@@ -307,6 +339,9 @@
     long _rxMinTimeoutMs;
     std::queue<StreamMetadata> _rxCmds;
     std::queue<StreamMetadata> _txResps;
+    std::string _xb200Mode;
+    std::string _samplingMode;
+    std::string _loopbackMode;
 
     bladerf *_dev;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_Streaming.cpp 
new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_Streaming.cpp
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/bladeRF_Streaming.cpp  2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/bladeRF_Streaming.cpp  2018-12-08 
04:19:47.000000000 +0100
@@ -89,14 +89,34 @@
 SoapySDR::Stream *bladeRF_SoapySDR::setupStream(
     const int direction,
     const std::string &format,
-    const std::vector<size_t> &channels,
+    const std::vector<size_t> &channels_,
     const SoapySDR::Kwargs &args)
 {
+    auto channels = channels_;
+    if (channels.empty()) channels.push_back(0);
+
     //check the channel configuration
+    #ifndef LIBBLADERF_V2
     if (channels.size() > 1 or (channels.size() > 0 and channels.at(0) != 0))
     {
         throw std::runtime_error("setupStream invalid channel selection");
     }
+    const auto layout = _toch(direction, 0);
+    #else
+    bladerf_channel_layout layout;
+    if (channels.size() == 1 and channels.at(0) == 0)
+    {
+        layout = (direction == SOAPY_SDR_RX)?BLADERF_RX_X1:BLADERF_TX_X1;
+    }
+    else if (channels.size() == 2 and channels.at(0) == 0 and channels.at(1) 
== 1)
+    {
+        layout = (direction == SOAPY_SDR_RX)?BLADERF_RX_X2:BLADERF_TX_X2;
+    }
+    else
+    {
+        throw std::runtime_error("setupStream invalid channel selection");
+    }
+    #endif
 
     //check the format
     if (format == "CF32") {}
@@ -122,7 +142,7 @@
     //setup the stream for sync tx/rx calls
     int ret = bladerf_sync_config(
         _dev,
-        _dir2mod(direction),
+        layout,
         BLADERF_FORMAT_SC16_Q11_META,
         numBuffs,
         bufSize,
@@ -135,7 +155,7 @@
     }
 
     //activate the stream here -- only call once
-    ret = bladerf_enable_module(_dev, _dir2mod(direction), true);
+    ret = bladerf_enable_module(_dev, _toch(direction, 0), true);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_enable_module(true) returned 
%d", ret);
@@ -166,7 +186,7 @@
     const int direction = *reinterpret_cast<int *>(stream);
 
     //deactivate the stream here -- only call once
-    const int ret = bladerf_enable_module(_dev, _dir2mod(direction), false);
+    const int ret = bladerf_enable_module(_dev, _toch(direction, 0), false);
     if (ret != 0)
     {
         SoapySDR::logf(SOAPY_SDR_ERROR, "bladerf_enable_module(false) returned 
%s", _err2str(ret).c_str());
@@ -384,7 +404,11 @@
         else
         {
             md.flags |= BLADERF_META_FLAG_TX_NOW;
+            #ifndef LIBBLADERF_V2
             bladerf_get_timestamp(_dev, BLADERF_MODULE_TX, &md.timestamp);
+            #else
+            bladerf_get_timestamp(_dev, BLADERF_TX, &md.timestamp);
+            #endif
         }
         _txNextTicks = md.timestamp;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/changelog 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/changelog
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/changelog       2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/changelog       2018-12-08 
04:19:47.000000000 +0100
@@ -1,3 +1,21 @@
+soapybladerf (0.4.0-1) unstable; urgency=low
+
+  * Release 0.4.0 (2018-12-07)
+
+ -- Josh Blum <j...@pothosware.com>  Fri, 07 Dec 2018 21:19:37 -0000
+
+soapybladerf (0.3.5-1) unstable; urgency=low
+
+  * Release 0.3.5 (2018-03-06)
+
+ -- Josh Blum <j...@pothosware.com>  Tue, 06 Mar 2018 19:55:10 -0000
+
+soapybladerf (0.3.4-1) unstable; urgency=low
+
+  * Release 0.3.4 (2018-01-16)
+
+ -- Josh Blum <j...@pothosware.com>  Tue, 16 Jan 2018 20:29:57 -0000
+
 soapybladerf (0.3.3-1) unstable; urgency=low
 
   * Release 0.3.3 (2017-04-29)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/control 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/control
--- old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/control 2017-04-30 
00:10:57.000000000 +0200
+++ new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/control 2018-12-08 
04:19:47.000000000 +0100
@@ -7,12 +7,12 @@
     cmake,
     libbladerf-dev,
     libsoapysdr-dev
-Standards-Version: 3.9.8
+Standards-Version: 4.1.4
 Homepage: https://github.com/pothosware/SoapyBladeRF/wiki
 Vcs-Git: https://github.com/pothosware/SoapyBladeRF.git
 Vcs-Browser: https://github.com/pothosware/SoapyBladeRF
 
-Package: soapysdr0.6-module-bladerf
+Package: soapysdr0.7-module-bladerf
 Architecture: any
 Multi-Arch: same
 Depends: ${shlibs:Depends}, ${misc:Depends}
@@ -21,7 +21,7 @@
 
 Package: soapysdr-module-bladerf
 Architecture: all
-Depends: soapysdr0.6-module-bladerf, ${misc:Depends}
+Depends: soapysdr0.7-module-bladerf, ${misc:Depends}
 Description: Soapy BladeRF - BladeRF device support for Soapy SDR.
  A Soapy module that supports BladeRF devices within the Soapy API.
  .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/soapysdr0.6-module-bladerf.install 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/soapysdr0.6-module-bladerf.install
--- 
old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/soapysdr0.6-module-bladerf.install  
    2017-04-30 00:10:57.000000000 +0200
+++ 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/soapysdr0.6-module-bladerf.install  
    1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-usr/lib/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/soapysdr0.7-module-bladerf.install 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/soapysdr0.7-module-bladerf.install
--- 
old/SoapyBladeRF-soapy-bladerf-0.3.3/debian/soapysdr0.7-module-bladerf.install  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/SoapyBladeRF-soapy-bladerf-0.4.0/debian/soapysdr0.7-module-bladerf.install  
    2018-12-08 04:19:47.000000000 +0100
@@ -0,0 +1 @@
+usr/lib/*


Reply via email to