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/*