[hamradio-commits] [soapysdr] 01/11: New upstream version 0.6.0
Andreas E. Bombe
aeb at moszumanska.debian.org
Tue Jun 27 01:08:58 UTC 2017
This is an automated email from the git hooks/post-receive script.
aeb pushed a commit to branch master
in repository soapysdr.
commit 9674426b3c685234d23494e812b054c2a6b01cb5
Author: Andreas Bombe <aeb at debian.org>
Date: Tue Jun 27 01:05:34 2017 +0200
New upstream version 0.6.0
---
.travis.yml | 41 ++---
CMakeLists.txt | 2 +-
Changelog.txt | 28 +++
README.md | 4 +-
apps/CMakeLists.txt | 1 +
apps/SoapyRateTest.cpp | 149 ++++++++++++++++
apps/SoapySDRProbe.cpp | 19 ++-
apps/SoapySDRUtil.cpp | 43 +++++
cmake/SoapySDRConfig.cmake | 2 +-
debian/changelog | 12 ++
debian/control | 10 +-
debian/copyright | 2 +-
...oapysdr0.5-2.install => libsoapysdr0.6.install} | 0
include/SoapySDR/Device.h | 190 +++++++++++++++------
include/SoapySDR/Device.hpp | 118 ++++++++++---
include/SoapySDR/Modules.h | 7 +
include/SoapySDR/Modules.hpp | 6 +
include/SoapySDR/Types.h | 15 +-
include/SoapySDR/Types.hpp | 26 ++-
include/SoapySDR/Version.h | 32 +++-
lib/Device.cpp | 53 +++++-
lib/DeviceC.cpp | 134 +++++++++------
lib/Factory.cpp | 110 +++++-------
lib/FactoryC.cpp | 6 +-
lib/LoggerC.cpp | 3 +-
lib/Modules.in.cpp | 11 +-
lib/ModulesC.cpp | 7 +-
lib/TypeHelpers.hpp | 19 ++-
lib/Types.cpp | 62 ++++++-
lib/TypesC.cpp | 13 +-
python/CMakeLists.txt | 25 ++-
python/SoapySDR.i | 26 ++-
python/apps/SimpleSiggen.py | 2 +-
python3/CMakeLists.txt | 6 +-
tests/CMakeLists.txt | 4 +
tests/TestKwargsMarkup.cpp | 76 +++++++++
36 files changed, 995 insertions(+), 269 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 527dc45..d0f335c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,17 +12,25 @@ sudo: required
dist: trusty
language: cpp
-compiler: gcc
+
+matrix:
+ include:
+ - os: linux
+ compiler: gcc
+ env:
+ global:
+ - PYTHON_EXECUTABLE=/usr/bin/python
+ - PYTHON3_EXECUTABLE=/usr/bin/python3
+ - os: osx
+ compiler: clang
+ env:
+ global:
+ - PYTHON_EXECUTABLE=/usr/local/bin/python
+ - PYTHON3_EXECUTABLE=/usr/local/bin/python3
env:
global:
- INSTALL_PREFIX=/usr/local
- - PYTHON_EXECUTABLE=/usr/bin/python
- - PYTHON_INSTALL_DIR=lib/python2.7/dist-packages
- - PYTHON3_EXECUTABLE=/usr/bin/python3
- - PYTHON3_INSTALL_DIR=lib/python3/dist-packages
- matrix:
- - BUILD_TYPE=Debug
- BUILD_TYPE=Release
# whitelist
@@ -31,26 +39,19 @@ branches:
- master
- maint
-before_install:
- # regular ubuntu packages
- - sudo add-apt-repository main
- - sudo add-apt-repository universe
-
- # update after package changes
- - sudo apt-get update
-
install:
# install python support dependencies
- - sudo apt-get install -qq python python-dev python-numpy swig
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq python python-dev python-numpy swig; fi;
# install python3 support dependencies
- - sudo apt-get install -qq python3 python3-dev python3-numpy swig
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq python3 python3-dev python3-numpy swig; fi;
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install swig python3 ; fi
script:
- mkdir build
- cd build
- - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DPYTHON3_EXECUTABLE=${PYTHON3_EXECUTABLE}
+ - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DUSE_PYTHON_CONFIG=ON -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DPYTHON3_EXECUTABLE=${PYTHON3_EXECUTABLE}
- make
- sudo make install
@@ -64,7 +65,7 @@ script:
- SoapySDRUtil --make="driver=null"
# basic test for python bindings
- - export PYTHONPATH=${INSTALL_PREFIX}/${PYTHON_INSTALL_DIR}:/usr/${PYTHON_INSTALL_DIR}
+ - export PYTHONPATH=$(${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True, prefix='${INSTALL_PREFIX}'))")
- echo ${PYTHONPATH}
- ${PYTHON_EXECUTABLE} -c "import SoapySDR; print(SoapySDR.getAPIVersion())"
- ${PYTHON_EXECUTABLE} -c "from SoapySDR import *; print(SOAPY_SDR_ABI_VERSION)"
@@ -73,7 +74,7 @@ script:
- ${PYTHON_EXECUTABLE} -c "import SoapySDR; print(SoapySDR.Device.make('driver=null'))"
# basic test for python3 bindings
- - export PYTHONPATH=${INSTALL_PREFIX}/${PYTHON3_INSTALL_DIR}:/usr/${PYTHON3_INSTALL_DIR}
+ - export PYTHONPATH=$(${PYTHON3_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True, prefix='${INSTALL_PREFIX}'))")
- echo ${PYTHONPATH}
- ${PYTHON3_EXECUTABLE} -c "import SoapySDR; print(SoapySDR.getAPIVersion())"
- ${PYTHON3_EXECUTABLE} -c "from SoapySDR import *; print(SOAPY_SDR_ABI_VERSION)"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f06553..c541a30 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ enable_testing()
# gather version information
# packagers may specify -DSOAPY_SDR_EXTVER="foo" to replace the git hash
########################################################################
-set(SOAPY_SDR_LIBVER "0.5.4")
+set(SOAPY_SDR_LIBVER "0.6.0")
if (NOT SOAPY_SDR_EXTVER)
include(${PROJECT_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake)
diff --git a/Changelog.txt b/Changelog.txt
index dc7cddd..1c9fe2a 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,5 +1,33 @@
This this the changelog file for the SoapySDR project.
+Release 0.6.0 (2017-04-29)
+==========================
+
+Device C API changes:
+
+- Device readI2C - make numBytes an in/out argument
+- Device read/write registers switch to named variant
+- Status return for Device C API calls with void return
+
+General additions and changes:
+
+- Added frequency corrections API for fine adjustments
+- Added getSampleRateRange() API for continuous ranges
+- Device factory table keys based on enumeration results
+- Added optional step size to the range type
+- Added rate testing to SoapySDRUtil application
+- Added listSearchPaths() API and SoapySDRUtil print
+- Added Kwargs type to/from markup string API calls
+- Added read/writeRegisters() API for bulk register IO
+
+Release 0.5.5 (2017-04-28)
+==========================
+
+- Added logger API and constants to python SWIG bindings
+- Added missing time utils to the swig python support
+- Fixed missing INFO log level for SOAPY_SDR_LOG_LEVEL
+- Fix for cache overwrite of PYTHON_INSTALL_DIR variable
+
Release 0.5.4 (2016-11-29)
==========================
diff --git a/README.md b/README.md
index 2494865..843e908 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# Soapy SDR - vendor and platform neutral SDR support library.
-##Build Status
+## Build Status
- Travis: [](https://travis-ci.org/pothosware/SoapySDR)
- AppVeyor: [](https://ci.appveyor.com/project/guruofquality/soapysdr)
-##Documentation
+## Documentation
* https://github.com/pothosware/SoapySDR/wiki
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 124eca1..edbf3f2 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -4,6 +4,7 @@
set(SOAPY_SDR_UTIL_SOURCES
SoapySDRUtil.cpp
SoapySDRProbe.cpp
+ SoapyRateTest.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
if (MSVC)
diff --git a/apps/SoapyRateTest.cpp b/apps/SoapyRateTest.cpp
new file mode 100644
index 0000000..fc953b8
--- /dev/null
+++ b/apps/SoapyRateTest.cpp
@@ -0,0 +1,149 @@
+// Copyright (c) 2016-2016 Josh Blum
+// SPDX-License-Identifier: BSL-1.0
+
+#include <SoapySDR/Device.hpp>
+#include <SoapySDR/Formats.hpp>
+#include <SoapySDR/Errors.hpp>
+#include <string>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <csignal>
+#include <chrono>
+#include <cstdio>
+
+static sig_atomic_t loopDone = false;
+void sigIntHandler(const int)
+{
+ loopDone = true;
+}
+
+void runRateTestStreamLoop(
+ SoapySDR::Device *device,
+ SoapySDR::Stream *stream,
+ const int direction,
+ const size_t numChans,
+ const size_t elemSize)
+{
+ //allocate buffers for the stream read/write
+ const size_t numElems = device->getStreamMTU(stream);
+ std::vector<std::vector<char>> buffMem(numChans, std::vector<char>(elemSize*numElems));
+ std::vector<void *> buffs(numChans);
+ for (size_t i = 0; i < numChans; i++) buffs[i] = buffMem[i].data();
+
+ //state collected in this loop
+ unsigned int overflows(0);
+ unsigned int underflows(0);
+ unsigned long long totalSamples(0);
+ const auto startTime = std::chrono::high_resolution_clock::now();
+ auto timeLastPrint = std::chrono::high_resolution_clock::now();
+
+ std::cout << "Starting stream loop, press Ctrl+C to exit..." << std::endl;
+ device->activateStream(stream);
+ signal(SIGINT, sigIntHandler);
+ while (not loopDone)
+ {
+ int ret(0);
+ int flags(0);
+ long long timeNs(0);
+ switch(direction)
+ {
+ case SOAPY_SDR_RX:
+ ret = device->readStream(stream, buffs.data(), numElems, flags, timeNs);
+ break;
+ case SOAPY_SDR_TX:
+ ret = device->writeStream(stream, buffs.data(), numElems, flags, timeNs);
+ break;
+ }
+
+ if (ret == SOAPY_SDR_TIMEOUT) continue;
+ if (ret == SOAPY_SDR_OVERFLOW)
+ {
+ overflows++;
+ continue;
+ }
+ if (ret == SOAPY_SDR_UNDERFLOW)
+ {
+ underflows++;
+ continue;
+ }
+ if (ret < 0)
+ {
+ std::cerr << "Unexpected stream error " << SoapySDR::errToStr(ret) << std::endl;
+ break;
+ }
+ totalSamples += ret;
+
+ const auto now = std::chrono::high_resolution_clock::now();
+ if (timeLastPrint + std::chrono::seconds(5) < now)
+ {
+ timeLastPrint = now;
+ const auto timePassed = std::chrono::duration_cast<std::chrono::microseconds>(now - startTime);
+ const auto sampleRate = double(totalSamples)/timePassed.count();
+ printf("%g Msps\t%g Bps", sampleRate, sampleRate*numChans*elemSize);
+ if (overflows != 0) printf("\tOverflows %u", overflows);
+ if (underflows != 0) printf("\tUnderflows %u", underflows);
+ printf("\n");
+ }
+
+ }
+ device->deactivateStream(stream);
+}
+
+int SoapySDRRateTest(
+ const std::string &argStr,
+ const double sampleRate,
+ const std::string &channelStr,
+ const std::string &directionStr)
+{
+ SoapySDR::Device *device(nullptr);
+
+ try
+ {
+ device = SoapySDR::Device::make(argStr);
+
+ //parse the direction to the integer enum
+ int direction(-1);
+ if (directionStr == "RX" or directionStr == "rx") direction = SOAPY_SDR_RX;
+ if (directionStr == "TX" or directionStr == "tx") direction = SOAPY_SDR_TX;
+ if (direction == -1) throw std::invalid_argument("direction not in RX/TX: " + directionStr);
+
+ //build channels list, using KwargsFromString is a easy parsing hack
+ std::vector<size_t> channels;
+ for (const auto &pair : SoapySDR::KwargsFromString(channelStr))
+ {
+ channels.push_back(std::stoi(pair.first));
+ }
+ if (channels.empty()) channels.push_back(0);
+
+ //initialize the sample rate for all channels
+ for (const auto &chan : channels)
+ {
+ device->setSampleRate(direction, chan, sampleRate);
+ }
+
+ //create the stream, use the native format
+ double fullScale(0.0);
+ const auto format = device->getNativeStreamFormat(direction, channels.front(), fullScale);
+ const size_t elemSize = SoapySDR::formatToSize(format);
+ auto stream = device->setupStream(direction, format, channels);
+
+ //run the rate test one setup is complete
+ std::cout << "Stream format: " << format << std::endl;
+ std::cout << "Num channels: " << channels.size() << std::endl;
+ std::cout << "Element size: " << elemSize << " bytes" << std::endl;
+ std::cout << "Begin " << directionStr << " rate test at " << (sampleRate/1e6) << " Msps" << std::endl;
+ runRateTestStreamLoop(device, stream, direction, channels.size(), elemSize);
+
+ //cleanup stream and device
+ device->closeStream(stream);
+ SoapySDR::Device::unmake(device);
+ }
+ catch (const std::exception &ex)
+ {
+ std::cerr << "Error in rate test: " << ex.what() << std::endl;
+ SoapySDR::Device::unmake(device);
+ return EXIT_FAILURE;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/apps/SoapySDRProbe.cpp b/apps/SoapySDRProbe.cpp
index 228bafc..cb353de 100644
--- a/apps/SoapySDRProbe.cpp
+++ b/apps/SoapySDRProbe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2016 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// Copyright (c) 2016-2016 Bastille Networks
// SPDX-License-Identifier: BSL-1.0
@@ -21,17 +21,26 @@ std::string toString(const std::vector<Type> &options)
std::string toString(const SoapySDR::Range &range)
{
std::stringstream ss;
- ss << "[" << range.minimum() << ", " << range.maximum() << "]";
+ ss << "[" << range.minimum() << ", " << range.maximum();
+ if (range.step() != 0.0) ss << ", " << range.step();
+ ss << "]";
return ss.str();
}
std::string toString(const SoapySDR::RangeList &range, const double scale)
{
+ const size_t MAXRLEN = 10; //for abbreviating long lists
std::stringstream ss;
for (size_t i = 0; i < range.size(); i++)
{
+ if (range.size() >= MAXRLEN and i >= MAXRLEN/2 and i < (range.size()-MAXRLEN/2))
+ {
+ if (i == MAXRLEN) ss << ", ...";
+ continue;
+ }
if (not ss.str().empty()) ss << ", ";
- ss << "[" << (range[i].minimum()/scale) << ", " << (range[i].maximum()/scale) << "]";
+ if (range[i].minimum() == range[i].maximum()) ss << (range[i].minimum()/scale);
+ else ss << "[" << (range[i].minimum()/scale) << ", " << (range[i].maximum()/scale) << "]";
}
return ss.str();
}
@@ -179,10 +188,10 @@ static std::string probeChannel(SoapySDR::Device *device, const int dir, const s
if (not freqArgs.empty()) ss << " Tune args:" << std::endl << freqArgs;
//rates
- ss << " Sample rates: " << toString(device->listSampleRates(dir, chan), 1e6) << " MHz" << std::endl;
+ ss << " Sample rates: " << toString(device->getSampleRateRange(dir, chan), 1e6) << " MSps" << std::endl;
//bandwidths
- const std::vector<double> bws = device->listBandwidths(dir, chan);
+ const auto bws = device->getBandwidthRange(dir, chan);
if (not bws.empty()) ss << " Filter bandwidths: " << toString(bws, 1e6) << " MHz" << std::endl;
//sensors
diff --git a/apps/SoapySDRUtil.cpp b/apps/SoapySDRUtil.cpp
index ed52a0a..7cd6e05 100644
--- a/apps/SoapySDRUtil.cpp
+++ b/apps/SoapySDRUtil.cpp
@@ -11,6 +11,11 @@
#include <getopt.h>
std::string SoapySDRDeviceProbe(SoapySDR::Device *);
+int SoapySDRRateTest(
+ const std::string &argStr,
+ const double sampleRate,
+ const std::string &channelStr,
+ const std::string &directionStr);
/***********************************************************************
* Print help message
@@ -26,6 +31,13 @@ static int printHelp(void)
std::cout << " --probe[=\"driver=foo,type=bar\"] \t Print detailed information" << std::endl;
std::cout << " --check[=driverName] \t\t Check if driver is present" << std::endl;
std::cout << std::endl;
+
+ std::cout << " Rate testing options:" << std::endl;
+ std::cout << " --args[=\"driver=foo\"] \t\t Arguments for testing" << std::endl;
+ std::cout << " --rate[=stream rate Sps] \t\t Rate in samples per second" << std::endl;
+ std::cout << " --channels[=\"0, 1, 2\"] \t\t List of channels, default 0" << std::endl;
+ std::cout << " --direction[=RX or TX] \t\t Specify the channel direction" << std::endl;
+ std::cout << std::endl;
return EXIT_SUCCESS;
}
@@ -39,6 +51,9 @@ static int printInfo(void)
std::cout << "ABI Version: v" << SoapySDR::getABIVersion() << std::endl;
std::cout << "Install root: " << SoapySDR::getRootPath() << std::endl;
+ for (const auto &path : SoapySDR::listSearchPaths())
+ std::cout << "Search path: " << path << std::endl;
+
const auto modules = SoapySDR::listModules();
for (const auto &mod : modules) std::cout << "Module found: " << mod << std::endl;
if (modules.empty()) std::cout << "No modules found!" << std::endl;
@@ -172,6 +187,11 @@ int main(int argc, char *argv[])
std::cout << "######################################################" << std::endl;
std::cout << std::endl;
+ std::string argStr;
+ std::string chanStr;
+ std::string dirStr;
+ double sampleRate(0.0);
+
/*******************************************************************
* parse command line options
******************************************************************/
@@ -182,6 +202,11 @@ int main(int argc, char *argv[])
{"info", optional_argument, 0, 'i'},
{"probe", optional_argument, 0, 'p'},
{"check", optional_argument, 0, 'c'},
+
+ {"args", optional_argument, 0, 'a'},
+ {"rate", optional_argument, 0, 'r'},
+ {"channels", optional_argument, 0, 'n'},
+ {"direction", optional_argument, 0, 'd'},
{0, 0, 0, 0}
};
int long_index = 0;
@@ -196,9 +221,27 @@ int main(int argc, char *argv[])
case 'm': return makeDevice();
case 'p': return probeDevice();
case 'c': return checkDriver();
+ case 'a':
+ if (optarg != nullptr) argStr = optarg;
+ break;
+ case 'r':
+ if (optarg != nullptr) sampleRate = std::stod(optarg);
+ break;
+ case 'n':
+ if (optarg != nullptr) chanStr = optarg;
+ break;
+ case 'd':
+ if (optarg != nullptr) dirStr = optarg;
+ break;
}
}
+ //invoke utilities that rely on multiple arguments
+ if (sampleRate != 0.0)
+ {
+ return SoapySDRRateTest(argStr, sampleRate, chanStr, dirStr);
+ }
+
//unknown or unspecified options, do help...
return printHelp();
}
diff --git a/cmake/SoapySDRConfig.cmake b/cmake/SoapySDRConfig.cmake
index 984e1a0..682ccaf 100644
--- a/cmake/SoapySDRConfig.cmake
+++ b/cmake/SoapySDRConfig.cmake
@@ -119,7 +119,7 @@ endif()
########################################################################
function(_SOAPY_SDR_GET_ABI_VERSION VERSION SOAPY_SDR_INCLUDE_DIR)
file(READ "${SOAPY_SDR_INCLUDE_DIR}/SoapySDR/Version.h" version_h)
- string(REGEX MATCH "\\#define SOAPY_SDR_ABI_VERSION \"([0-9]+\\.[0-9]+-[0-9]+)\"" SOAPY_SDR_ABI_VERSION_MATCHES "${version_h}")
+ string(REGEX MATCH "\\#define SOAPY_SDR_ABI_VERSION \"([0-9]+\\.[0-9]+(-[A-Za-z0-9]+)?)\"" SOAPY_SDR_ABI_VERSION_MATCHES "${version_h}")
if(NOT SOAPY_SDR_ABI_VERSION_MATCHES)
message(FATAL_ERROR "Failed to extract version number from Version.h")
endif(NOT SOAPY_SDR_ABI_VERSION_MATCHES)
diff --git a/debian/changelog b/debian/changelog
index 34cb1a6..ff973ba 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+soapysdr (0.6.0-1) unstable; urgency=low
+
+ * Release 0.6.0 (2017-04-29)
+
+ -- Josh Blum <josh at pothosware.com> Sat, 29 Apr 2017 08:35:26 -0000
+
+soapysdr (0.5.5-1) unstable; urgency=low
+
+ * Release 0.5.5 (2017-04-28)
+
+ -- Josh Blum <josh at pothosware.com> Fri, 28 Apr 2017 21:53:39 -0000
+
soapysdr (0.5.4-ppa1) unstable; urgency=low
* Release 0.5.4 (2016-11-29)
diff --git a/debian/control b/debian/control
index ddd69a9..1112831 100644
--- a/debian/control
+++ b/debian/control
@@ -15,7 +15,7 @@ Homepage: https://github.com/pothosware/SoapySDR/wiki
Vcs-Git: https://github.com/pothosware/SoapySDR.git
Vcs-Browser: https://github.com/pothosware/SoapySDR
-Package: libsoapysdr0.5-2
+Package: libsoapysdr0.6
Section: libs
Architecture: any
Multi-Arch: same
@@ -32,7 +32,7 @@ Package: libsoapysdr-dev
Section: libdevel
Architecture: any
Depends:
- libsoapysdr0.5-2 (= ${binary:Version}),
+ libsoapysdr0.6 (= ${binary:Version}),
${misc:Depends}
Description: SoapySDR library development files
SoapySDR is a library providing a common interface to SDR (software
@@ -44,7 +44,7 @@ Description: SoapySDR library development files
Package: soapysdr
Architecture: any
Depends:
- libsoapysdr0.5-2 (= ${binary:Version}),
+ libsoapysdr0.6 (= ${binary:Version}),
${shlibs:Depends},
${misc:Depends}
Description: software defined radio interface library tools
@@ -59,7 +59,7 @@ Package: python-soapysdr
Section: python
Architecture: any
Depends:
- libsoapysdr0.5-2 (= ${binary:Version}),
+ libsoapysdr0.6 (= ${binary:Version}),
python,
${shlibs:Depends},
${misc:Depends}
@@ -75,7 +75,7 @@ Package: python3-soapysdr
Section: python
Architecture: any
Depends:
- libsoapysdr0.5-2 (= ${binary:Version}),
+ libsoapysdr0.6 (= ${binary:Version}),
python3,
${shlibs:Depends},
${misc:Depends}
diff --git a/debian/copyright b/debian/copyright
index 3166daa..9c0ac39 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@ Source: https://github.com/pothosware/SoapySDR/wiki
Files: *
Copyright:
- Copyright (c) 2014-2016 Josh Blum <josh at pothosware.com>
+ Copyright (c) 2014-2017 Josh Blum <josh at pothosware.com>
Copyright (c) 2016-2016 Bastille Networks
License: BSL-1.0
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/debian/libsoapysdr0.5-2.install b/debian/libsoapysdr0.6.install
similarity index 100%
rename from debian/libsoapysdr0.5-2.install
rename to debian/libsoapysdr0.6.install
diff --git a/include/SoapySDR/Device.h b/include/SoapySDR/Device.h
index 8c78c3e..7edfeea 100644
--- a/include/SoapySDR/Device.h
+++ b/include/SoapySDR/Device.h
@@ -8,7 +8,7 @@
/// The caller must free non-const array results.
///
/// \copyright
-/// Copyright (c) 2014-2016 Josh Blum
+/// Copyright (c) 2014-2017 Josh Blum
/// Copyright (c) 2016-2016 Bastille Networks
/// SPDX-License-Identifier: BSL-1.0
///
@@ -84,19 +84,17 @@ SOAPY_SDR_API SoapySDRDevice *SoapySDRDevice_make(const SoapySDRKwargs *args);
* For every call to make, there should be a matched call to unmake.
*
* \param args a markup string of key/value arguments
- * \return a pointer to a new Device object
+ * \return a pointer to a new Device object or null for error
*/
SOAPY_SDR_API SoapySDRDevice *SoapySDRDevice_makeStrArgs(const char *args);
/*!
* Unmake or release a device object handle.
*
- * \note This call is not thread safe. Implementations calling into unmake
- * from multiple threads should protect this call with a mutex.
- *
* \param device a pointer to a device object
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_unmake(SoapySDRDevice *device);
+SOAPY_SDR_API int SoapySDRDevice_unmake(SoapySDRDevice *device);
/*******************************************************************
* Identification API
@@ -186,7 +184,8 @@ SOAPY_SDR_API bool SoapySDRDevice_getFullDuplex(const SoapySDRDevice *device, co
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
* \param [out] length the number of format strings
- * \return a list of allowed format strings
+ * \return a list of allowed format strings.
+ * See SoapySDRDevice_setupStream() for the format syntax.
*/
SOAPY_SDR_API char **SoapySDRDevice_getStreamFormats(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length);
@@ -214,34 +213,55 @@ SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getStreamArgsInfo(const SoapySDRDe
/*!
* Initialize a stream given a list of channels and stream arguments.
+ * The implementation may change switches or power-up components.
* All stream API calls should be usable with the new stream object
* after setupStream() is complete, regardless of the activity state.
*
- * Format string markup guidelines:
- * - C means complex
- * - F means floating point
- * - S means signed integer
- * - U means unsigned integer
- * - number float/int size in bytes (complex is 2x this size)
- *
- * Example format strings:
- * - CF32 complex float32 (8 bytes per element)
- * - CS16 complex int16 (4 bytes per element)
- * - CS12 complex int12 (3 bytes per element)
- * - CS4 complex int4 (1 byte per element)
- * - S32 int32 (4 bytes per element)
- * - U8 uint8 (1 byte per element)
+ * The API allows any number of simultaneous TX and RX streams, but many dual-channel
+ * devices are limited to one stream in each direction, using either one or both channels.
+ * This call will return an error if an unsupported combination is requested,
+ * or if a requested channel in this direction is already in use by another stream.
*
- * Recommended keys to use in the args dictionary:
- * - "WIRE" - format of the samples between device and host
+ * When multiple channels are added to a stream, they are typically expected to have
+ * the same sample rate. See SoapySDRDevice_setSampleRate().
*
* \param device a pointer to a device instance
- * \param [out] stream the opaque pointer to a stream handle
- * \param direction the channel direction RX or TX
- * \param format the desired buffer format in read/writeStream()
- * \param channels a list of channels for empty for automatic
+ * \param [out] stream the opaque pointer to a stream handle.
+ * \parblock
+ *
+ * The returned stream is not required to have internal locking, and may not be used
+ * concurrently from multiple threads.
+ * \endparblock
+ *
+ * \param direction the channel direction (`SOAPY_SDR_RX` or `SOAPY_SDR_TX`)
+ * \param format A string representing the desired buffer format in read/writeStream()
+ * \parblock
+ *
+ * The first character selects the number type:
+ * - "C" means complex
+ * - "F" means floating point
+ * - "S" means signed integer
+ * - "U" means unsigned integer
+ *
+ * The type character is followed by the number of bits per number (complex is 2x this size per sample)
+ *
+ * Example format strings:
+ * - "CF32" - complex float32 (8 bytes per element)
+ * - "CS16" - complex int16 (4 bytes per element)
+ * - "CS12" - complex int12 (3 bytes per element)
+ * - "CS4" - complex int4 (1 byte per element)
+ * - "S32" - int32 (4 bytes per element)
+ * - "U8" - uint8 (1 byte per element)
+ *
+ * \endparblock
+ * \param channels a list of channels or empty for automatic
* \param numChans the number of elements in the channels array
* \param args stream args or empty for defaults
+ * \parblock
+ *
+ * Recommended keys to use in the args dictionary:
+ * - "WIRE" - format of the samples between device and host
+ * \endparblock
* \return 0 for success or error code on failure
*/
SOAPY_SDR_API int SoapySDRDevice_setupStream(SoapySDRDevice *device,
@@ -256,8 +276,9 @@ SOAPY_SDR_API int SoapySDRDevice_setupStream(SoapySDRDevice *device,
* Close an open stream created by setupStream
* \param device a pointer to a device instance
* \param stream the opaque pointer to a stream handle
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_closeStream(SoapySDRDevice *device, SoapySDRStream *stream);
+SOAPY_SDR_API int SoapySDRDevice_closeStream(SoapySDRDevice *device, SoapySDRStream *stream);
/*!
* Get the stream's maximum transmission unit (MTU) in number of elements.
@@ -612,8 +633,9 @@ SOAPY_SDR_API int SoapySDRDevice_setDCOffset(SoapySDRDevice *device, const int d
* \param channel an available channel on the device
* \param [out] offsetI the relative correction (1.0 max)
* \param [out] offsetQ the relative correction (1.0 max)
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_getDCOffset(const SoapySDRDevice *device, const int direction, const size_t channel, double *offsetI, double *offsetQ);
+SOAPY_SDR_API int SoapySDRDevice_getDCOffset(const SoapySDRDevice *device, const int direction, const size_t channel, double *offsetI, double *offsetQ);
/*!
* Does the device support frontend IQ balance correction?
@@ -642,8 +664,37 @@ SOAPY_SDR_API int SoapySDRDevice_setIQBalance(SoapySDRDevice *device, const int
* \param channel an available channel on the device
* \param [out] balanceI the relative correction (1.0 max)
* \param [out] balanceQ the relative correction (1.0 max)
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_getIQBalance(const SoapySDRDevice *device, const int direction, const size_t channel, double *balanceI, double *balanceQ);
+SOAPY_SDR_API int SoapySDRDevice_getIQBalance(const SoapySDRDevice *device, const int direction, const size_t channel, double *balanceI, double *balanceQ);
+
+/*!
+ * Does the device support frontend frequency correction?
+ * \param device a pointer to a device instance
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \return true if frequency corrections are supported
+ */
+SOAPY_SDR_API bool SoapySDRDevice_hasFrequencyCorrection(const SoapySDRDevice *device, const int direction, const size_t channel);
+
+/*!
+ * Fine tune the frontend frequency correction.
+ * \param device a pointer to a device instance
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \param value the correction in PPM
+ * \return an error code or 0 for success
+ */
+SOAPY_SDR_API int SoapySDRDevice_setFrequencyCorrection(SoapySDRDevice *device, const int direction, const size_t channel, const double value);
+
+/*!
+ * Get the frontend frequency correction value.
+ * \param device a pointer to a device instance
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \return the correction value in PPM
+ */
+SOAPY_SDR_API double SoapySDRDevice_getFrequencyCorrection(const SoapySDRDevice *device, const int direction, const size_t channel);
/*******************************************************************
* Gain API
@@ -891,6 +942,7 @@ SOAPY_SDR_API double SoapySDRDevice_getSampleRate(const SoapySDRDevice *device,
/*!
* Get the range of possible baseband sample rates.
+ * \deprecated replaced by getSampleRateRange()
* \param device a pointer to a device instance
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
@@ -899,6 +951,16 @@ SOAPY_SDR_API double SoapySDRDevice_getSampleRate(const SoapySDRDevice *device,
*/
SOAPY_SDR_API double *SoapySDRDevice_listSampleRates(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length);
+/*!
+ * Get the range of possible baseband sample rates.
+ * \param device a pointer to a device instance
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \param [out] length the number of sample rates
+ * \return a list of sample rate ranges in samples per second
+ */
+SOAPY_SDR_API SoapySDRRange *SoapySDRDevice_getSampleRateRange(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length);
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -1043,8 +1105,9 @@ SOAPY_SDR_API long long SoapySDRDevice_getHardwareTime(const SoapySDRDevice *dev
* \param device a pointer to a device instance
* \param timeNs time in nanoseconds
* \param what optional argument
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_setHardwareTime(SoapySDRDevice *device, const long long timeNs, const char *what);
+SOAPY_SDR_API int SoapySDRDevice_setHardwareTime(SoapySDRDevice *device, const long long timeNs, const char *what);
/*!
* Set the time of subsequent configuration calls.
@@ -1054,8 +1117,9 @@ SOAPY_SDR_API void SoapySDRDevice_setHardwareTime(SoapySDRDevice *device, const
* \param device a pointer to a device instance
* \param timeNs time in nanoseconds
* \param what optional argument
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_setCommandTime(SoapySDRDevice *device, const long long timeNs, const char *what);
+SOAPY_SDR_API int SoapySDRDevice_setCommandTime(SoapySDRDevice *device, const long long timeNs, const char *what);
/*******************************************************************
* Sensor API
@@ -1143,8 +1207,9 @@ SOAPY_SDR_API char **SoapySDRDevice_listRegisterInterfaces(const SoapySDRDevice
* \param name the name of a available register interface
* \param addr the register address
* \param value the register value
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeNamedRegister(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned value);
+SOAPY_SDR_API int SoapySDRDevice_writeRegister(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned value);
/*!
* Read a register on the device given the interface name.
@@ -1153,27 +1218,32 @@ SOAPY_SDR_API void SoapySDRDevice_writeNamedRegister(SoapySDRDevice *device, con
* \param addr the register address
* \return the register value
*/
-SOAPY_SDR_API unsigned SoapySDRDevice_readNamedRegister(const SoapySDRDevice *device, const char *name, const unsigned addr);
+SOAPY_SDR_API unsigned SoapySDRDevice_readRegister(const SoapySDRDevice *device, const char *name, const unsigned addr);
/*!
- * Write a register on the device.
- * This can represent a register on a soft CPU, FPGA, IC;
+ * Write a memory block on the device given the interface name.
+ * This can represent a memory block on a soft CPU, FPGA, IC;
* the interpretation is up the implementation to decide.
- * \deprecated replaced by writeRegister(name)
* \param device a pointer to a device instance
- * \param addr the register address
- * \param value the register value
+ * \param name the name of a available memory block interface
+ * \param addr the memory block start address
+ * \param value the memory block content
+ * \param length the number of words in the block
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeRegister(SoapySDRDevice *device, const unsigned addr, const unsigned value);
+SOAPY_SDR_API int SoapySDRDevice_writeRegisters(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned *value, const size_t length);
/*!
- * Read a register on the device.
- * \deprecated replaced by readRegister(name)
+ * Read a memory block on the device given the interface name.
+ * Pass the number of words to be read in via length;
+ * length will be set to the number of actual words read.
* \param device a pointer to a device instance
- * \param addr the register address
- * \return the register value
+ * \param name the name of a available memory block interface
+ * \param addr the memory block start address
+ * \param [inout] length number of words to be read from memory block
+ * \return the memory block content
*/
-SOAPY_SDR_API unsigned SoapySDRDevice_readRegister(const SoapySDRDevice *device, const unsigned addr);
+SOAPY_SDR_API unsigned *SoapySDRDevice_readRegisters(const SoapySDRDevice *device, const char *name, const unsigned addr, size_t *length);
/*******************************************************************
* Settings API
@@ -1193,8 +1263,9 @@ SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getSettingInfo(const SoapySDRDevic
* \param device a pointer to a device instance
* \param key the setting identifier
* \param value the setting value
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeSetting(SoapySDRDevice *device, const char *key, const char *value);
+SOAPY_SDR_API int SoapySDRDevice_writeSetting(SoapySDRDevice *device, const char *key, const char *value);
/*!
* Read an arbitrary setting on the device.
@@ -1222,8 +1293,9 @@ SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getChannelSettingInfo(const SoapyS
* \param channel an available channel on the device
* \param key the setting identifier
* \param value the setting value
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeChannelSetting(SoapySDRDevice *device, const int direction, const size_t channel, const char *key, const char *value);
+SOAPY_SDR_API int SoapySDRDevice_writeChannelSetting(SoapySDRDevice *device, const int direction, const size_t channel, const char *key, const char *value);
/*!
* Read an arbitrary channel setting on the device.
@@ -1251,8 +1323,9 @@ SOAPY_SDR_API char **SoapySDRDevice_listGPIOBanks(const SoapySDRDevice *device,
* \param device a pointer to a device instance
* \param bank the name of an available bank
* \param value an integer representing GPIO bits
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *bank, const unsigned value);
+SOAPY_SDR_API int SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *bank, const unsigned value);
/*!
* Write the value of a GPIO bank with modification mask.
@@ -1260,8 +1333,9 @@ SOAPY_SDR_API void SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *
* \param bank the name of an available bank
* \param value an integer representing GPIO bits
* \param mask a modification mask where 1 = modify
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeGPIOMasked(SoapySDRDevice *device, const char *bank, const unsigned value, const unsigned mask);
+SOAPY_SDR_API int SoapySDRDevice_writeGPIOMasked(SoapySDRDevice *device, const char *bank, const unsigned value, const unsigned mask);
/*!
* Readback the value of a GPIO bank.
@@ -1277,8 +1351,9 @@ SOAPY_SDR_API unsigned SoapySDRDevice_readGPIO(const SoapySDRDevice *device, con
* \param device a pointer to a device instance
* \param bank the name of an available bank
* \param dir an integer representing data direction bits
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const char *bank, const unsigned dir);
+SOAPY_SDR_API int SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const char *bank, const unsigned dir);
/*!
* Write the data direction of a GPIO bank with modification mask.
@@ -1287,8 +1362,9 @@ SOAPY_SDR_API void SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const cha
* \param bank the name of an available bank
* \param dir an integer representing data direction bits
* \param mask a modification mask where 1 = modify
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeGPIODirMasked(SoapySDRDevice *device, const char *bank, const unsigned dir, const unsigned mask);
+SOAPY_SDR_API int SoapySDRDevice_writeGPIODirMasked(SoapySDRDevice *device, const char *bank, const unsigned dir, const unsigned mask);
/*!
* Read the data direction of a GPIO bank.
@@ -1311,19 +1387,22 @@ SOAPY_SDR_API unsigned SoapySDRDevice_readGPIODir(const SoapySDRDevice *device,
* \param addr the address of the slave
* \param data an array of bytes write out
* \param numBytes the number of bytes to write
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeI2C(SoapySDRDevice *device, const int addr, const char *data, const size_t numBytes);
+SOAPY_SDR_API int SoapySDRDevice_writeI2C(SoapySDRDevice *device, const int addr, const char *data, const size_t numBytes);
/*!
* Read from an available I2C slave.
* If the device contains multiple I2C masters,
* the address bits can encode which master.
+ * Pass the number of bytes to be read in via numBytes;
+ * numBytes will be set to the number of actual bytes read.
* \param device a pointer to a device instance
* \param addr the address of the slave
- * \param numBytes the number of bytes to read
+ * \param [inout] numBytes the number of bytes to read
* \return an array of bytes read from the slave
*/
-SOAPY_SDR_API char *SoapySDRDevice_readI2C(SoapySDRDevice *device, const int addr, const size_t numBytes);
+SOAPY_SDR_API char *SoapySDRDevice_readI2C(SoapySDRDevice *device, const int addr, size_t *numBytes);
/*******************************************************************
* SPI API
@@ -1365,8 +1444,9 @@ SOAPY_SDR_API char **SoapySDRDevice_listUARTs(const SoapySDRDevice *device, size
* \param device a pointer to a device instance
* \param which the name of an available UART
* \param data a null terminated array of bytes
+ * \return 0 for success or error code on failure
*/
-SOAPY_SDR_API void SoapySDRDevice_writeUART(SoapySDRDevice *device, const char *which, const char *data);
+SOAPY_SDR_API int SoapySDRDevice_writeUART(SoapySDRDevice *device, const char *which, const char *data);
/*!
* Read bytes from a UART until timeout or newline.
diff --git a/include/SoapySDR/Device.hpp b/include/SoapySDR/Device.hpp
index 496a077..16865c9 100644
--- a/include/SoapySDR/Device.hpp
+++ b/include/SoapySDR/Device.hpp
@@ -4,7 +4,7 @@
/// Interface definition for Soapy SDR devices.
///
/// \copyright
-/// Copyright (c) 2014-2016 Josh Blum
+/// Copyright (c) 2014-2017 Josh Blum
/// Copyright (c) 2016-2016 Bastille Networks
/// SPDX-License-Identifier: BSL-1.0
///
@@ -75,9 +75,6 @@ public:
/*!
* Unmake or release a device object handle.
*
- * \note This call is not thread safe. Implementations calling into unmake
- * from multiple threads should protect this call with a mutex.
- *
* \param device a pointer to a device object
*/
static void unmake(Device *device);
@@ -161,7 +158,7 @@ public:
* Query a list of the available stream formats.
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
- * \return a list of allowed format strings
+ * \return a list of allowed format strings. See setupStream() for the format syntax.
*/
virtual std::vector<std::string> getStreamFormats(const int direction, const size_t channel) const;
@@ -190,29 +187,48 @@ public:
* All stream API calls should be usable with the new stream object
* after setupStream() is complete, regardless of the activity state.
*
- * Format string markup guidelines:
- * - C means complex
- * - F means floating point
- * - S means signed integer
- * - U means unsigned integer
- * - number float/int size in bytes (complex is 2x this size)
+ * The API allows any number of simultaneous TX and RX streams, but many dual-channel
+ * devices are limited to one stream in each direction, using either one or both channels.
+ * This call will throw an exception if an unsupported combination is requested,
+ * or if a requested channel in this direction is already in use by another stream.
*
- * Example format strings:
- * - CF32 complex float32 (8 bytes per element)
- * - CS16 complex int16 (4 bytes per element)
- * - CS12 complex int12 (3 bytes per element)
- * - CS4 complex int4 (1 byte per element)
- * - S32 int32 (4 bytes per element)
- * - U8 uint8 (1 byte per element)
+ * When multiple channels are added to a stream, they are typically expected to have
+ * the same sample rate. See setSampleRate().
*
- * Recommended keys to use in the args dictionary:
- * - "WIRE" - format of the samples between device and host
+ * \param direction the channel direction (`SOAPY_SDR_RX` or `SOAPY_SDR_TX`)
+ * \param format A string representing the desired buffer format in read/writeStream()
+ * \parblock
*
- * \param direction the channel direction RX or TX
- * \param format the desired buffer format in read/writeStream()
- * \param channels a list of channels for empty for automatic
- * \param args stream args or empty for defaults
- * \return an opaque pointer to a stream handle
+ * The first character selects the number type:
+ * - "C" means complex
+ * - "F" means floating point
+ * - "S" means signed integer
+ * - "U" means unsigned integer
+ *
+ * The type character is followed by the number of bits per number (complex is 2x this size per sample)
+ *
+ * Example format strings:
+ * - "CF32" - complex float32 (8 bytes per element)
+ * - "CS16" - complex int16 (4 bytes per element)
+ * - "CS12" - complex int12 (3 bytes per element)
+ * - "CS4" - complex int4 (1 byte per element)
+ * - "S32" - int32 (4 bytes per element)
+ * - "U8" - uint8 (1 byte per element)
+ *
+ * \endparblock
+ * \param channels a list of channels or empty for automatic.
+ * \param args stream args or empty for defaults.
+ * \parblock
+ *
+ * Recommended keys to use in the args dictionary:
+ * - "WIRE" - format of the samples between device and host
+ * \endparblock
+ * \return an opaque pointer to a stream handle.
+ * \parblock
+ *
+ * The returned stream is not required to have internal locking, and may not be used
+ * concurrently from multiple threads.
+ * \endparblock
*/
virtual Stream *setupStream(
const int direction,
@@ -580,6 +596,30 @@ public:
*/
virtual std::complex<double> getIQBalance(const int direction, const size_t channel) const;
+ /*!
+ * Does the device support frontend frequency correction?
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \return true if frequency corrections are supported
+ */
+ virtual bool hasFrequencyCorrection(const int direction, const size_t channel) const;
+
+ /*!
+ * Fine tune the frontend frequency correction.
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \param value the correction in PPM
+ */
+ virtual void setFrequencyCorrection(const int direction, const size_t channel, const double value);
+
+ /*!
+ * Get the frontend frequency correction value.
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \return the correction value in PPM
+ */
+ virtual double getFrequencyCorrection(const int direction, const size_t channel) const;
+
/*******************************************************************
* Gain API
******************************************************************/
@@ -795,12 +835,21 @@ public:
/*!
* Get the range of possible baseband sample rates.
+ * \deprecated replaced by getSampleRateRange()
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
* \return a list of possible rates in samples per second
*/
virtual std::vector<double> listSampleRates(const int direction, const size_t channel) const;
+ /*!
+ * Get the range of possible baseband sample rates.
+ * \param direction the channel direction RX or TX
+ * \param channel an available channel on the device
+ * \return a list of sample rate ranges in samples per second
+ */
+ virtual RangeList getSampleRateRange(const int direction, const size_t channel) const;
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -1037,6 +1086,25 @@ public:
*/
virtual unsigned readRegister(const unsigned addr) const;
+ /*!
+ * Write a memory block on the device given the interface name.
+ * This can represent a memory block on a soft CPU, FPGA, IC;
+ * the interpretation is up the implementation to decide.
+ * \param name the name of a available memory block interface
+ * \param addr the memory block start address
+ * \param value the memory block content
+ */
+ virtual void writeRegisters(const std::string &name, const unsigned addr, const std::vector<unsigned> &value);
+
+ /*!
+ * Read a memory block on the device given the interface name.
+ * \param name the name of a available memory block interface
+ * \param addr the memory block start address
+ * \param length number of words to be read from memory block
+ * \return the memory block content
+ */
+ virtual std::vector<unsigned> readRegisters(const std::string &name, const unsigned addr, const size_t length) const;
+
/*******************************************************************
* Settings API
******************************************************************/
diff --git a/include/SoapySDR/Modules.h b/include/SoapySDR/Modules.h
index 67d74b6..b064043 100644
--- a/include/SoapySDR/Modules.h
+++ b/include/SoapySDR/Modules.h
@@ -23,6 +23,13 @@ extern "C" {
SOAPY_SDR_API const char *SoapySDR_getRootPath(void);
/*!
+ * The list of paths automatically searched by loadModules().
+ * \param [out] length the number of elements in the result.
+ * \return a list of automatically searched file paths
+ */
+SOAPY_SDR_API char **SoapySDR_listSearchPaths(size_t *length);
+
+/*!
* List all modules found in default path.
* The result is an array of strings owned by the caller.
* \param [out] length the number of elements in the result.
diff --git a/include/SoapySDR/Modules.hpp b/include/SoapySDR/Modules.hpp
index 8a1e77c..267df77 100644
--- a/include/SoapySDR/Modules.hpp
+++ b/include/SoapySDR/Modules.hpp
@@ -23,6 +23,12 @@ namespace SoapySDR
SOAPY_SDR_API std::string getRootPath(void);
/*!
+ * The list of paths automatically searched by loadModules().
+ * \return a list of automatically searched file paths
+ */
+SOAPY_SDR_API std::vector<std::string> listSearchPaths(void);
+
+/*!
* List all modules found in default path.
* \return a list of file paths to loadable modules
*/
diff --git a/include/SoapySDR/Types.h b/include/SoapySDR/Types.h
index 33caf52..b4a9542 100644
--- a/include/SoapySDR/Types.h
+++ b/include/SoapySDR/Types.h
@@ -4,7 +4,7 @@
/// Misc data type definitions used in the API.
///
/// \copyright
-/// Copyright (c) 2014-2015 Josh Blum
+/// Copyright (c) 2014-2017 Josh Blum
/// SPDX-License-Identifier: BSL-1.0
///
@@ -21,6 +21,7 @@ typedef struct
{
double minimum;
double maximum;
+ double step;
} SoapySDRRange;
//! Definition for a key/value string map
@@ -31,6 +32,18 @@ typedef struct
char **vals;
} SoapySDRKwargs;
+/*!
+ * Convert a markup string to a key-value map.
+ * The markup format is: "key0=value0, key1=value1"
+ */
+SOAPY_SDR_API SoapySDRKwargs SoapySDRKwargs_fromString(const char *markup);
+
+/*!
+ * Convert a key-value map to a markup string.
+ * The markup format is: "key0=value0, key1=value1"
+ */
+SOAPY_SDR_API char *SoapySDRKwargs_toString(const SoapySDRKwargs *args);
+
//! Possible data types for argument info
typedef enum
{
diff --git a/include/SoapySDR/Types.hpp b/include/SoapySDR/Types.hpp
index 74ccbf3..f9ad013 100644
--- a/include/SoapySDR/Types.hpp
+++ b/include/SoapySDR/Types.hpp
@@ -4,7 +4,7 @@
/// Misc data type definitions used in the API.
///
/// \copyright
-/// Copyright (c) 2014-2015 Josh Blum
+/// Copyright (c) 2014-2017 Josh Blum
/// SPDX-License-Identifier: BSL-1.0
///
@@ -21,6 +21,18 @@ namespace SoapySDR
//! Typedef for a dictionary of key-value string arguments
typedef std::map<std::string, std::string> Kwargs;
+/*!
+ * Convert a markup string to a key-value map.
+ * The markup format is: "key0=value0, key1=value1"
+ */
+SOAPY_SDR_API Kwargs KwargsFromString(const std::string &markup);
+
+/*!
+ * Convert a key-value map to a markup string.
+ * The markup format is: "key0=value0, key1=value1"
+ */
+SOAPY_SDR_API std::string KwargsToString(const Kwargs &args);
+
//! Typedef for a list of key-word dictionaries
typedef std::vector<Kwargs> KwargsList;
@@ -35,7 +47,7 @@ public:
Range(void);
//! Create a min/max range
- Range(const double minimum, const double maximum);
+ Range(const double minimum, const double maximum, const double step=0.0);
//! Get the range minimum
double minimum(void) const;
@@ -43,8 +55,11 @@ public:
//! Get the range maximum
double maximum(void) const;
+ //! Get the range step size
+ double step(void) const;
+
private:
- double _min, _max;
+ double _min, _max, _step;
};
/*!
@@ -122,3 +137,8 @@ inline double SoapySDR::Range::maximum(void) const
{
return _max;
}
+
+inline double SoapySDR::Range::step(void) const
+{
+ return _step;
+}
diff --git a/include/SoapySDR/Version.h b/include/SoapySDR/Version.h
index 7af432b..11280aa 100644
--- a/include/SoapySDR/Version.h
+++ b/include/SoapySDR/Version.h
@@ -4,7 +4,7 @@
/// Utility functions to query version information.
///
/// \copyright
-/// Copyright (c) 2014-2016 Josh Blum
+/// Copyright (c) 2014-2017 Josh Blum
/// Copyright (c) 2016-2016 Bastille Networks
/// SPDX-License-Identifier: BSL-1.0
///
@@ -26,16 +26,16 @@
* #endif
* \endcode
*/
-#define SOAPY_SDR_API_VERSION 0x00050002
+#define SOAPY_SDR_API_VERSION 0x00060000
/*!
* ABI Version Information - incremented when the ABI is changed.
- * The ABI version format is <b>major.minor-bump</b>. The <i>major.minor</i>
- * comes from the in-progress library version when the change was made,
- * and <i>bump</i> signifies a change to the ABI during library development.
+ * The ABI version format is <b>version[-extra]</b>.
+ * The <i>version</i> comes from the associated library major.minor version.
+ * And <i>extra</i> is empty for releases but set on development branches.
* The ABI should remain constant across patch releases of the library.
*/
-#define SOAPY_SDR_ABI_VERSION "0.5-2"
+#define SOAPY_SDR_ABI_VERSION "0.6"
/*!
* Compatibility define for GPIO access API with masks
@@ -122,6 +122,26 @@
*/
#define SOAPY_SDR_API_HAS_NAMED_REGISTER_API
+/*!
+ * Compatibility define for named memory block interface API
+ */
+#define SOAPY_SDR_API_HAS_NAMED_REGISTERS_API
+
+/*!
+ * Compatibility define for step field in range type
+ */
+#define SOAPY_SDR_API_HAS_RANGE_TYPE_STEP
+
+/*!
+ * Compatibility define for get sample rate range API
+ */
+#define SOAPY_SDR_API_HAS_GET_SAMPLE_RATE_RANGE
+
+/*!
+ * Compatibility define for frequency correction API
+ */
+#define SOAPY_SDR_API_HAS_FREQUENCY_CORRECTION_API
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/lib/Device.cpp b/lib/Device.cpp
index f2490da..dc88253 100644
--- a/lib/Device.cpp
+++ b/lib/Device.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2014-2016 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// Copyright (c) 2016-2016 Bastille Networks
// SPDX-License-Identifier: BSL-1.0
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Formats.hpp>
#include <cstdlib>
-#include <algorithm> //min/max
+#include <algorithm> //min/max/find
SoapySDR::Device::~Device(void)
{
@@ -218,6 +218,34 @@ std::complex<double> SoapySDR::Device::getIQBalance(const int, const size_t) con
return std::complex<double>();
}
+bool SoapySDR::Device::hasFrequencyCorrection(const int direction, const size_t channel) const
+{
+ //backwards compatibility with "CORR" string arg
+ const auto components = this->listFrequencies(direction, channel);
+ return (std::find(components.begin(), components.end(), "CORR") != components.end());
+}
+
+void SoapySDR::Device::setFrequencyCorrection(const int direction, const size_t channel, const double value)
+{
+ //backwards compatibility with "CORR" string arg
+ const auto components = this->listFrequencies(direction, channel);
+ if (std::find(components.begin(), components.end(), "CORR") != components.end())
+ {
+ this->setFrequency(direction, channel, "CORR", value);
+ }
+}
+
+double SoapySDR::Device::getFrequencyCorrection(const int direction, const size_t channel) const
+{
+ //backwards compatibility with "CORR" string arg
+ const auto components = this->listFrequencies(direction, channel);
+ if (std::find(components.begin(), components.end(), "CORR") != components.end())
+ {
+ return this->getFrequency(direction, channel, "CORR");
+ }
+ return 0.0;
+}
+
/*******************************************************************
* Gain API
******************************************************************/
@@ -480,6 +508,17 @@ std::vector<double> SoapySDR::Device::listSampleRates(const int, const size_t) c
return std::vector<double>();
}
+SoapySDR::RangeList SoapySDR::Device::getSampleRateRange(const int direction, const size_t channel) const
+{
+ SoapySDR::RangeList ranges;
+ //call into the older deprecated listSampleRates() call
+ for (auto &bw : this->listSampleRates(direction, channel))
+ {
+ ranges.push_back(SoapySDR::Range(bw, bw));
+ }
+ return ranges;
+}
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -642,6 +681,16 @@ unsigned SoapySDR::Device::readRegister(const unsigned) const
return 0;
}
+void SoapySDR::Device::writeRegisters(const std::string &, const unsigned, const std::vector<unsigned> &)
+{
+ return;
+}
+
+std::vector<unsigned> SoapySDR::Device::readRegisters(const std::string &, const unsigned, size_t length) const
+{
+ return std::vector<unsigned>(length, 0);
+}
+
/*******************************************************************
* Settings API
******************************************************************/
diff --git a/lib/DeviceC.cpp b/lib/DeviceC.cpp
index 900ce78..1fe7707 100644
--- a/lib/DeviceC.cpp
+++ b/lib/DeviceC.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// Copyright (c) 2016-2016 Bastille Networks
// SPDX-License-Identifier: BSL-1.0
@@ -51,7 +51,7 @@ const char *SoapySDRDevice_lastError(void)
static const bool SoapySDRBoolErr = bool(-1);
-static const SoapySDRRange SoapySDRRangeNAN = {NAN, NAN};
+static const SoapySDRRange SoapySDRRangeNAN = {NAN, NAN, 0.0};
static SoapySDRArgInfo SoapySDRArgInfoNull(void)
{
@@ -164,11 +164,11 @@ int SoapySDRDevice_setupStream(SoapySDRDevice *device, SoapySDRStream **stream,
//__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_closeStream(SoapySDRDevice *device, SoapySDRStream *stream)
+int SoapySDRDevice_closeStream(SoapySDRDevice *device, SoapySDRStream *stream)
{
__SOAPY_SDR_C_TRY
- return device->closeStream(reinterpret_cast<SoapySDR::Stream *>(stream));
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->closeStream(reinterpret_cast<SoapySDR::Stream *>(stream));
+ __SOAPY_SDR_C_CATCH
}
size_t SoapySDRDevice_getStreamMTU(const SoapySDRDevice *device, SoapySDRStream *stream)
@@ -345,13 +345,13 @@ int SoapySDRDevice_setDCOffset(SoapySDRDevice *device, const int direction, cons
__SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_getDCOffset(const SoapySDRDevice *device, const int direction, const size_t channel, double *offsetI, double *offsetQ)
+int SoapySDRDevice_getDCOffset(const SoapySDRDevice *device, const int direction, const size_t channel, double *offsetI, double *offsetQ)
{
__SOAPY_SDR_C_TRY
std::complex<double> ret = device->getDCOffset(direction, channel);
*offsetI = ret.real();
*offsetQ = ret.imag();
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ __SOAPY_SDR_C_CATCH
}
bool SoapySDRDevice_hasIQBalance(const SoapySDRDevice *device, const int direction, const size_t channel)
@@ -368,13 +368,34 @@ int SoapySDRDevice_setIQBalance(SoapySDRDevice *device, const int direction, con
__SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_getIQBalance(const SoapySDRDevice *device, const int direction, const size_t channel, double *balanceI, double *balanceQ)
+int SoapySDRDevice_getIQBalance(const SoapySDRDevice *device, const int direction, const size_t channel, double *balanceI, double *balanceQ)
{
__SOAPY_SDR_C_TRY
std::complex<double> ret = device->getIQBalance(direction, channel);
*balanceI = ret.real();
*balanceQ = ret.imag();
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ __SOAPY_SDR_C_CATCH
+}
+
+bool SoapySDRDevice_hasFrequencyCorrection(const SoapySDRDevice *device, const int direction, const size_t channel)
+{
+ __SOAPY_SDR_C_TRY
+ return device->hasFrequencyCorrection(direction, channel);
+ __SOAPY_SDR_C_CATCH_RET(SoapySDRBoolErr);
+}
+
+int SoapySDRDevice_setFrequencyCorrection(SoapySDRDevice *device, const int direction, const size_t channel, const double value)
+{
+ __SOAPY_SDR_C_TRY
+ device->setFrequencyCorrection(direction, channel, value);
+ __SOAPY_SDR_C_CATCH
+}
+
+double SoapySDRDevice_getFrequencyCorrection(const SoapySDRDevice *device, const int direction, const size_t channel)
+{
+ __SOAPY_SDR_C_TRY
+ return device->getFrequencyCorrection(direction, channel);
+ __SOAPY_SDR_C_CATCH_RET(NAN);
}
/*******************************************************************
@@ -539,6 +560,14 @@ double *SoapySDRDevice_listSampleRates(const SoapySDRDevice *device, const int d
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
+SoapySDRRange *SoapySDRDevice_getSampleRateRange(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length)
+{
+ *length = 0;
+ __SOAPY_SDR_C_TRY
+ return toRangeList(device->getSampleRateRange(direction, channel), length);
+ __SOAPY_SDR_C_CATCH_RET(nullptr);
+}
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -659,18 +688,18 @@ long long SoapySDRDevice_getHardwareTime(const SoapySDRDevice *device, const cha
__SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_setHardwareTime(SoapySDRDevice *device, const long long timeNs, const char *what)
+int SoapySDRDevice_setHardwareTime(SoapySDRDevice *device, const long long timeNs, const char *what)
{
__SOAPY_SDR_C_TRY
device->setHardwareTime(timeNs, what);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ __SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_setCommandTime(SoapySDRDevice *device, const long long timeNs, const char *what)
+int SoapySDRDevice_setCommandTime(SoapySDRDevice *device, const long long timeNs, const char *what)
{
__SOAPY_SDR_C_TRY
device->setCommandTime(timeNs, what);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ __SOAPY_SDR_C_CATCH
}
/*******************************************************************
@@ -731,32 +760,35 @@ char **SoapySDRDevice_listRegisterInterfaces(const SoapySDRDevice *device, size_
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_writeNamedRegister(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned value)
+int SoapySDRDevice_writeRegister(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned value)
{
__SOAPY_SDR_C_TRY
- return device->writeRegister(name, addr, value);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeRegister(name, addr, value);
+ __SOAPY_SDR_C_CATCH
}
-unsigned SoapySDRDevice_readNamedRegister(const SoapySDRDevice *device, const char *name, const unsigned addr)
+unsigned SoapySDRDevice_readRegister(const SoapySDRDevice *device, const char *name, const unsigned addr)
{
__SOAPY_SDR_C_TRY
return device->readRegister(name, addr);
__SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_writeRegister(SoapySDRDevice *device, const unsigned addr, const unsigned value)
+int SoapySDRDevice_writeRegisters(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned *value, const size_t length)
{
__SOAPY_SDR_C_TRY
- return device->writeRegister(addr, value);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeRegisters(name, addr, toNumericVector(value, length));
+ __SOAPY_SDR_C_CATCH
}
-unsigned SoapySDRDevice_readRegister(const SoapySDRDevice *device, const unsigned addr)
+unsigned *SoapySDRDevice_readRegisters(const SoapySDRDevice *device, const char *name, const unsigned addr, size_t *length)
{
+ const size_t inputLen = *length;
+ *length = 0; //clear in case of error
+
__SOAPY_SDR_C_TRY
- return device->readRegister(addr);
- __SOAPY_SDR_C_CATCH
+ return toNumericList(device->readRegisters(name, addr, inputLen), length);
+ __SOAPY_SDR_C_CATCH_RET(nullptr);
}
/*******************************************************************
@@ -770,11 +802,11 @@ SoapySDRArgInfo *SoapySDRDevice_getSettingInfo(const SoapySDRDevice *device, siz
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_writeSetting(SoapySDRDevice *device, const char *key, const char *value)
+int SoapySDRDevice_writeSetting(SoapySDRDevice *device, const char *key, const char *value)
{
__SOAPY_SDR_C_TRY
- return device->writeSetting(key, value);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeSetting(key, value);
+ __SOAPY_SDR_C_CATCH
}
char *SoapySDRDevice_readSetting(const SoapySDRDevice *device, const char *key)
@@ -792,11 +824,11 @@ SoapySDRArgInfo *SoapySDRDevice_getChannelSettingInfo(const SoapySDRDevice *devi
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_writeChannelSetting(SoapySDRDevice *device, const int direction, const size_t channel, const char *key, const char *value)
+int SoapySDRDevice_writeChannelSetting(SoapySDRDevice *device, const int direction, const size_t channel, const char *key, const char *value)
{
__SOAPY_SDR_C_TRY
- return device->writeSetting(direction, channel, key, value);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeSetting(direction, channel, key, value);
+ __SOAPY_SDR_C_CATCH
}
char *SoapySDRDevice_readChannelSetting(const SoapySDRDevice *device, const int direction, const size_t channel, const char *key)
@@ -817,18 +849,18 @@ char **SoapySDRDevice_listGPIOBanks(const SoapySDRDevice *device, size_t *length
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *bank, const unsigned value)
+int SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *bank, const unsigned value)
{
__SOAPY_SDR_C_TRY
- return device->writeGPIO(bank, value);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeGPIO(bank, value);
+ __SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_writeGPIOMasked(SoapySDRDevice *device, const char *bank, const unsigned value, const unsigned mask)
+int SoapySDRDevice_writeGPIOMasked(SoapySDRDevice *device, const char *bank, const unsigned value, const unsigned mask)
{
__SOAPY_SDR_C_TRY
- return device->writeGPIO(bank, value, mask);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeGPIO(bank, value, mask);
+ __SOAPY_SDR_C_CATCH
}
unsigned SoapySDRDevice_readGPIO(const SoapySDRDevice *device, const char *bank)
@@ -838,18 +870,18 @@ unsigned SoapySDRDevice_readGPIO(const SoapySDRDevice *device, const char *bank)
__SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const char *bank, const unsigned dir)
+int SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const char *bank, const unsigned dir)
{
__SOAPY_SDR_C_TRY
- return device->writeGPIODir(bank, dir);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeGPIODir(bank, dir);
+ __SOAPY_SDR_C_CATCH
}
-void SoapySDRDevice_writeGPIODirMasked(SoapySDRDevice *device, const char *bank, const unsigned dir, const unsigned mask)
+int SoapySDRDevice_writeGPIODirMasked(SoapySDRDevice *device, const char *bank, const unsigned dir, const unsigned mask)
{
__SOAPY_SDR_C_TRY
- return device->writeGPIODir(bank, dir, mask);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeGPIODir(bank, dir, mask);
+ __SOAPY_SDR_C_CATCH
}
unsigned SoapySDRDevice_readGPIODir(const SoapySDRDevice *device, const char *bank)
@@ -862,19 +894,23 @@ unsigned SoapySDRDevice_readGPIODir(const SoapySDRDevice *device, const char *ba
/*******************************************************************
* I2C API
******************************************************************/
-void SoapySDRDevice_writeI2C(SoapySDRDevice *device, const int addr, const char *data, const size_t numBytes)
+int SoapySDRDevice_writeI2C(SoapySDRDevice *device, const int addr, const char *data, const size_t numBytes)
{
__SOAPY_SDR_C_TRY
- return device->writeI2C(addr, std::string(data, numBytes));
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeI2C(addr, std::string(data, numBytes));
+ __SOAPY_SDR_C_CATCH
}
-char *SoapySDRDevice_readI2C(SoapySDRDevice *device, const int addr, const size_t numBytes)
+char *SoapySDRDevice_readI2C(SoapySDRDevice *device, const int addr, size_t *numBytes)
{
+ const size_t inputNumBytes = *numBytes;
+ *numBytes = 0; //clear in case of error
+
__SOAPY_SDR_C_TRY
- const std::string bytes = device->readI2C(addr, numBytes).c_str();
+ const std::string bytes = device->readI2C(addr, inputNumBytes).c_str();
char *buff = (char *)std::malloc(bytes.size());
std::copy(bytes.begin(), bytes.end(), buff);
+ *numBytes = bytes.size();
return buff;
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
@@ -900,11 +936,11 @@ char **SoapySDRDevice_listUARTs(const SoapySDRDevice *device, size_t *length)
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_writeUART(SoapySDRDevice *device, const char *which, const char *data)
+int SoapySDRDevice_writeUART(SoapySDRDevice *device, const char *which, const char *data)
{
__SOAPY_SDR_C_TRY
- return device->writeUART(which, data);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ device->writeUART(which, data);
+ __SOAPY_SDR_C_CATCH
}
char *SoapySDRDevice_readUART(const SoapySDRDevice *device, const char *which, const long timeoutUs)
diff --git a/lib/Factory.cpp b/lib/Factory.cpp
index 493c096..a5b4ee8 100644
--- a/lib/Factory.cpp
+++ b/lib/Factory.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include <SoapySDR/Device.hpp>
@@ -6,7 +6,6 @@
#include <SoapySDR/Modules.hpp>
#include <stdexcept>
#include <iostream>
-#include <cctype>
#include <mutex>
static std::recursive_mutex &getFactoryMutex(void)
@@ -61,103 +60,72 @@ SoapySDR::KwargsList SoapySDR::Device::enumerate(const Kwargs &args)
return results;
}
-static std::string trim(const std::string &s)
+SoapySDR::KwargsList SoapySDR::Device::enumerate(const std::string &args)
{
- std::string out = s;
- while (not out.empty() and std::isspace(out[0])) out = out.substr(1);
- while (not out.empty() and std::isspace(out[out.size()-1])) out = out.substr(0, out.size()-1);
- return out;
+ return enumerate(KwargsFromString(args));
}
-static SoapySDR::Kwargs argsStrToKwargs(const std::string &args)
+static SoapySDR::Device* getDeviceFromTable(const SoapySDR::Kwargs &args)
{
- SoapySDR::Kwargs kwargs;
-
- bool inKey = true;
- std::string key, val;
- for (size_t i = 0; i < args.size(); i++)
+ if (args.empty()) return nullptr;
+ std::lock_guard<std::recursive_mutex> lock(getFactoryMutex());
+ if (getDeviceTable().count(args) != 0 and getDeviceCounts().count(getDeviceTable().at(args)) != 0)
{
- const char ch = args[i];
- if (inKey)
- {
- if (ch == '=') inKey = false;
- else if (ch == ',') inKey = true;
- else key += ch;
- }
- else
- {
- if (ch == ',') inKey = true;
- else val += ch;
- }
- if ((inKey and not val.empty()) or ((i+1) == args.size()))
- {
- key = trim(key);
- val = trim(val);
- if (not key.empty()) kwargs[key] = val;
- key = "";
- val = "";
- }
+ auto device = getDeviceTable().at(args);
+ getDeviceCounts()[device]++;
+ return device;
}
-
- return kwargs;
+ return nullptr;
}
-SoapySDR::KwargsList SoapySDR::Device::enumerate(const std::string &args)
+SoapySDR::Device* SoapySDR::Device::make(const Kwargs &inputArgs)
{
- return enumerate(argsStrToKwargs(args));
-}
+ Device *device = nullptr;
-SoapySDR::Device* SoapySDR::Device::make(const Kwargs &args_)
-{
- std::lock_guard<std::recursive_mutex> lock(getFactoryMutex());
+ //the arguments may have already come from enumerate and been used to open a device
+ device = getDeviceFromTable(inputArgs);
+ if (device != nullptr) return device;
- loadModules();
- Kwargs args = args_;
- Device *device = nullptr;
+ //otherwise the args must always come from an enumeration result
+ Kwargs discoveredArgs;
+ const auto results = Device::enumerate(inputArgs);
+ if (not results.empty()) discoveredArgs = results.front();
//check the device table for an already allocated device
- if (getDeviceTable().count(args_) != 0 and getDeviceCounts().count(getDeviceTable().at(args_)) != 0)
- {
- device = getDeviceTable().at(args_);
- }
+ device = getDeviceFromTable(discoveredArgs);
+ if (device != nullptr) return device;
- //otherwise call into one of the factory functions
- else
+ //load the enumeration args with missing keys from the make argument
+ Kwargs hybridArgs = discoveredArgs;
+ for (const auto &it : inputArgs)
{
- //the args must always come from an enumeration result
- {
- const auto results = Device::enumerate(args);
- if (not results.empty()) args = results.front();
- }
+ if (hybridArgs.count(it.first) == 0) hybridArgs[it.first] = it.second;
+ }
- //load the enumeration args with missing keys from the make argument
- for (const auto &it : args_)
- {
- if (args.count(it.first) == 0) args[it.first] = it.second;
- }
+ //lock during device construction
+ //make itself can be parallelized, but we need to keep track of in-process factories
+ //so that other calling threads with the same args can wait on the result
+ std::lock_guard<std::recursive_mutex> lock(getFactoryMutex());
- //loop through make functions and call on module match
- for (const auto &it : Registry::listMakeFunctions())
- {
- if (args.count("driver") != 0 and args.at("driver") != it.first) continue;
- device = it.second(args);
- break;
- }
+ //loop through make functions and call on module match
+ for (const auto &it : Registry::listMakeFunctions())
+ {
+ if (hybridArgs.count("driver") != 0 and hybridArgs.at("driver") != it.first) continue;
+ device = it.second(hybridArgs);
+ break;
}
-
if (device == nullptr) throw std::runtime_error("SoapySDR::Device::make() no match");
//store into the table
- getDeviceTable()[args_] = device;
+ getDeviceTable()[discoveredArgs] = device;
getDeviceCounts()[device]++;
return device;
}
-
SoapySDR::Device *SoapySDR::Device::make(const std::string &args)
{
- return make(argsStrToKwargs(args));
+ return make(KwargsFromString(args));
}
void SoapySDR::Device::unmake(Device *device)
diff --git a/lib/FactoryC.cpp b/lib/FactoryC.cpp
index 67bce81..47ee8e4 100644
--- a/lib/FactoryC.cpp
+++ b/lib/FactoryC.cpp
@@ -18,7 +18,7 @@ SoapySDRKwargs *SoapySDRDevice_enumerate(const SoapySDRKwargs *args, size_t *len
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-SOAPY_SDR_API SoapySDRKwargs *SoapySDRDevice_enumerateStrArgs(const char *args, size_t *length)
+SoapySDRKwargs *SoapySDRDevice_enumerateStrArgs(const char *args, size_t *length)
{
*length = 0;
__SOAPY_SDR_C_TRY
@@ -40,11 +40,11 @@ SoapySDRDevice *SoapySDRDevice_makeStrArgs(const char *args)
__SOAPY_SDR_C_CATCH_RET(nullptr);
}
-void SoapySDRDevice_unmake(SoapySDRDevice *device)
+int SoapySDRDevice_unmake(SoapySDRDevice *device)
{
__SOAPY_SDR_C_TRY
SoapySDR::Device::unmake((SoapySDR::Device *)device);
- __SOAPY_SDR_C_CATCH_RET(SoapySDRVoidRet);
+ __SOAPY_SDR_C_CATCH
}
}
diff --git a/lib/LoggerC.cpp b/lib/LoggerC.cpp
index e9137e7..7a08ca0 100644
--- a/lib/LoggerC.cpp
+++ b/lib/LoggerC.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include <SoapySDR/Logger.h>
@@ -25,6 +25,7 @@ static SoapySDRLogLevel getDefaultLogLevel(void)
checkLogLevelEnvStr(ERROR);
checkLogLevelEnvStr(WARNING);
checkLogLevelEnvStr(NOTICE);
+ checkLogLevelEnvStr(INFO);
checkLogLevelEnvStr(DEBUG);
checkLogLevelEnvStr(TRACE);
diff --git a/lib/Modules.in.cpp b/lib/Modules.in.cpp
index a03f101..fedd425 100644
--- a/lib/Modules.in.cpp
+++ b/lib/Modules.in.cpp
@@ -114,7 +114,7 @@ static std::vector<std::string> searchModulePath(const std::string &path)
return modulePaths;
}
-std::vector<std::string> SoapySDR::listModules(void)
+std::vector<std::string> SoapySDR::listSearchPaths(void)
{
//the default search path
std::vector<std::string> searchPaths;
@@ -146,11 +146,16 @@ std::vector<std::string> SoapySDR::listModules(void)
searchPaths.push_back(pluginPath);
}
+ return searchPaths;
+}
+
+std::vector<std::string> SoapySDR::listModules(void)
+{
//traverse the search paths
std::vector<std::string> modules;
- for (size_t i = 0; i < searchPaths.size(); i++)
+ for (const auto &searchPath : SoapySDR::listSearchPaths())
{
- const std::vector<std::string> subModules = SoapySDR::listModules(searchPaths.at(i));
+ const std::vector<std::string> subModules = SoapySDR::listModules(searchPath);
modules.insert(modules.end(), subModules.begin(), subModules.end());
}
return modules;
diff --git a/lib/ModulesC.cpp b/lib/ModulesC.cpp
index 1894fd2..1ecf6ab 100644
--- a/lib/ModulesC.cpp
+++ b/lib/ModulesC.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 Josh Blum
+// Copyright (c) 2014-2016 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "TypeHelpers.hpp"
@@ -15,6 +15,11 @@ const char *SoapySDR_getRootPath(void)
return root.c_str();
}
+char **SoapySDR_listSearchPaths(size_t *length)
+{
+ return toStrArray(SoapySDR::listSearchPaths(), length);
+}
+
char **SoapySDR_listModules(size_t *length)
{
return toStrArray(SoapySDR::listModules(), length);
diff --git a/lib/TypeHelpers.hpp b/lib/TypeHelpers.hpp
index edcec52..9a856cf 100644
--- a/lib/TypeHelpers.hpp
+++ b/lib/TypeHelpers.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -29,6 +29,7 @@ static inline SoapySDRRange toRange(const SoapySDR::Range &range)
SoapySDRRange out;
out.minimum = range.minimum();
out.maximum = range.maximum();
+ out.step = range.step();
return out;
}
@@ -103,3 +104,19 @@ static inline SoapySDRArgInfo *toArgInfoList(const SoapySDR::ArgInfoList &infos,
*length = infos.size();
return out;
}
+
+static inline std::vector<unsigned> toNumericVector(const unsigned *values, size_t length)
+{
+ std::vector<unsigned> out (length, 0);
+ for (size_t i = 0; i < length; i++) out[i] = values[i];
+ return out;
+}
+
+static inline unsigned *toNumericList(const std::vector<unsigned> &values, size_t *length)
+{
+ unsigned *out = (unsigned *)calloc(values.size(), sizeof(unsigned));
+ for (size_t i = 0; i < values.size(); i++) out[i] = values[i];
+ *length = values.size();
+ return out;
+}
+
diff --git a/lib/Types.cpp b/lib/Types.cpp
index ae87e44..df53dd7 100644
--- a/lib/Types.cpp
+++ b/lib/Types.cpp
@@ -1,7 +1,62 @@
-// Copyright (c) 2014-2015 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include <SoapySDR/Types.hpp>
+#include <cctype>
+
+static std::string trim(const std::string &s)
+{
+ std::string out = s;
+ while (not out.empty() and std::isspace(out[0])) out = out.substr(1);
+ while (not out.empty() and std::isspace(out[out.size()-1])) out = out.substr(0, out.size()-1);
+ return out;
+}
+
+SoapySDR::Kwargs SoapySDR::KwargsFromString(const std::string &markup)
+{
+ SoapySDR::Kwargs kwargs;
+
+ bool inKey = true;
+ std::string key, val;
+ for (size_t i = 0; i < markup.size(); i++)
+ {
+ const char ch = markup[i];
+ if (inKey)
+ {
+ if (ch == '=') inKey = false;
+ else if (ch == ',') inKey = true;
+ else key += ch;
+ }
+ else
+ {
+ if (ch == ',') inKey = true;
+ else val += ch;
+ }
+ if ((inKey and (not val.empty() or (ch == ','))) or ((i+1) == markup.size()))
+ {
+ key = trim(key);
+ val = trim(val);
+ if (not key.empty()) kwargs[key] = val;
+ key = "";
+ val = "";
+ }
+ }
+
+ return kwargs;
+}
+
+std::string SoapySDR::KwargsToString(const SoapySDR::Kwargs &args)
+{
+ std::string markup;
+
+ for (const auto &pair : args)
+ {
+ if (not markup.empty()) markup += ", ";
+ markup += pair.first + "=" + pair.second;
+ }
+
+ return markup;
+}
SoapySDR::Range::Range(void):
_min(0.0),
@@ -10,9 +65,10 @@ SoapySDR::Range::Range(void):
return;
}
-SoapySDR::Range::Range(const double minimum, const double maximum):
+SoapySDR::Range::Range(const double minimum, const double maximum, const double step):
_min(minimum),
- _max(maximum)
+ _max(maximum),
+ _step(step)
{
return;
}
diff --git a/lib/TypesC.cpp b/lib/TypesC.cpp
index d545146..ad25ea3 100644
--- a/lib/TypesC.cpp
+++ b/lib/TypesC.cpp
@@ -1,12 +1,23 @@
-// Copyright (c) 2014-2015 Josh Blum
+// Copyright (c) 2014-2016 Josh Blum
// SPDX-License-Identifier: BSL-1.0
+#include "TypeHelpers.hpp"
#include <SoapySDR/Types.h>
#include <cstdlib>
#include <cstring>
extern "C" {
+SoapySDRKwargs SoapySDRKwargs_fromString(const char *markup)
+{
+ return toKwargs(SoapySDR::KwargsFromString(markup));
+}
+
+char *SoapySDRKwargs_toString(const SoapySDRKwargs *args)
+{
+ return strdup(SoapySDR::KwargsToString(toKwargs(args)).c_str());
+}
+
void SoapySDRStrings_clear(char ***elems, const size_t length)
{
for (size_t i = 0; i < length; i++)
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index cf80b36..c5776c5 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -32,9 +32,9 @@ execute_process(
COMMAND ${PYTHON_EXECUTABLE} -c
"from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True, prefix=''))"
OUTPUT_STRIP_TRAILING_WHITESPACE
- OUTPUT_VARIABLE PYTHON_INSTALL_DIR
+ OUTPUT_VARIABLE PYTHON_INSTALL_DIR_SYSCONF
)
-set(PYTHON_INSTALL_DIR ${PYTHON_INSTALL_DIR} CACHE STRING "python install prefix")
+set(PYTHON_INSTALL_DIR "${PYTHON_INSTALL_DIR_SYSCONF}" CACHE STRING "python install prefix")
message(STATUS "PYTHON_INSTALL_DIR: \${prefix}/${PYTHON_INSTALL_DIR}")
########################################################################
@@ -91,6 +91,25 @@ if(PYTHON_VERSION_STRING AND "${PYTHON_VERSION_STRING}" VERSION_LESS "3.0")
endif()
########################################################################
+## set the swig flags - shared with python3 build
+########################################################################
+set(CMAKE_SWIG_FLAGS -c++ -threads)
+
+#check for size_t issue on arm 32-bit platforms
+include(CheckCXXSourceCompiles)
+CHECK_CXX_SOURCE_COMPILES("
+ #include <cstddef>
+ int main() {
+ size_t *x = (unsigned int *)(NULL);
+ return 0; }" SIZE_T_IS_UNSIGNED_INT)
+
+if (SIZE_T_IS_UNSIGNED_INT)
+ list(APPEND CMAKE_SWIG_FLAGS -DSIZE_T_IS_UNSIGNED_INT)
+endif (SIZE_T_IS_UNSIGNED_INT)
+
+set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} PARENT_SCOPE)
+
+########################################################################
## Feature registration
########################################################################
include(FeatureSummary)
@@ -108,7 +127,7 @@ include(UseSWIG)
include_directories(${SoapySDR_INCLUDE_DIRS})
include_directories(${PYTHON_INCLUDE_DIRS})
-set(CMAKE_SWIG_FLAGS -c++ -threads)
+message(STATUS "CMAKE_SWIG_FLAGS=${CMAKE_SWIG_FLAGS}")
set_source_files_properties(SoapySDR.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(SoapySDR python SoapySDR.i)
diff --git a/python/SoapySDR.i b/python/SoapySDR.i
index 4702215..ee2affc 100644
--- a/python/SoapySDR.i
+++ b/python/SoapySDR.i
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 Josh Blum
+// Copyright (c) 2014-2017 Josh Blum
// Copyright (c) 2016-2016 Bastille Networks
// SPDX-License-Identifier: BSL-1.0
@@ -13,6 +13,8 @@
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Errors.hpp>
#include <SoapySDR/Formats.hpp>
+#include <SoapySDR/Time.hpp>
+#include <SoapySDR/Logger.hpp>
%}
////////////////////////////////////////////////////////////////////////
@@ -43,6 +45,13 @@
%include <std_map.i>
%include <SoapySDR/Types.hpp>
+//handle arm 32-bit case where size_t and unsigned are the same
+#ifdef SIZE_T_IS_UNSIGNED_INT
+%typedef unsigned int size_t;
+#else
+%template(SoapySDRUnsignedList) std::vector<unsigned>;
+#endif
+
%template(SoapySDRKwargs) std::map<std::string, std::string>;
%template(SoapySDRKwargsList) std::vector<SoapySDR::Kwargs>;
%template(SoapySDRArgInfoList) std::vector<SoapySDR::ArgInfo>;
@@ -68,7 +77,9 @@
%insert("python")
%{
def __str__(self):
- return "%s, %s"%(self.minimum(), self.maximum())
+ fields = [self.minimum(), self.maximum()]
+ if self.step() != 0.0: fields.append(self.step())
+ return ', '.join(['%g'%f for f in fields])
%}
};
@@ -105,6 +116,11 @@
%include <SoapySDR/Version.h>
%include <SoapySDR/Formats.h>
+%ignore SoapySDR_logf;
+%ignore SoapySDR_vlogf;
+%ignore SoapySDR_registerLogHandler;
+%include <SoapySDR/Logger.h>
+
////////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////////
@@ -112,6 +128,12 @@
%include <SoapySDR/Version.hpp>
%include <SoapySDR/Modules.hpp>
%include <SoapySDR/Formats.hpp>
+%include <SoapySDR/Time.hpp>
+
+%ignore SoapySDR::logf;
+%ignore SoapySDR::vlogf;
+%ignore SoapySDR::registerLogHandler;
+%include <SoapySDR/Logger.hpp>
////////////////////////////////////////////////////////////////////////
// Device object
diff --git a/python/apps/SimpleSiggen.py b/python/apps/SimpleSiggen.py
index 8ea7898..cc3f652 100644
--- a/python/apps/SimpleSiggen.py
+++ b/python/apps/SimpleSiggen.py
@@ -67,7 +67,7 @@ def siggen_app(
phaseAcc = phaseAccNext
while phaseAcc > math.pi*2: phaseAcc -= math.pi*2
- sr = sdr.writeStream(txStream, [sampsCh0], sampsCh0.size)
+ sr = sdr.writeStream(txStream, [sampsCh0], sampsCh0.size, timeoutUs=1000000)
if sr.ret != sampsCh0.size:
raise Exception("Expected writeStream() to consume all samples! %d"%sr.ret)
totalSamps += sr.ret
diff --git a/python3/CMakeLists.txt b/python3/CMakeLists.txt
index 554bdc2..9204837 100644
--- a/python3/CMakeLists.txt
+++ b/python3/CMakeLists.txt
@@ -28,9 +28,9 @@ execute_process(
COMMAND ${PYTHON3_EXECUTABLE} -c
"from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True, prefix=''))"
OUTPUT_STRIP_TRAILING_WHITESPACE
- OUTPUT_VARIABLE PYTHON3_INSTALL_DIR
+ OUTPUT_VARIABLE PYTHON3_INSTALL_DIR_SYSCONF
)
-set(PYTHON3_INSTALL_DIR ${PYTHON3_INSTALL_DIR} CACHE STRING "python3 install prefix")
+set(PYTHON3_INSTALL_DIR "${PYTHON3_INSTALL_DIR_SYSCONF}" CACHE STRING "python3 install prefix")
message(STATUS "PYTHON3_INSTALL_DIR: \${prefix}/${PYTHON3_INSTALL_DIR}")
########################################################################
@@ -73,7 +73,7 @@ configure_file(
${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i
@ONLY)
-set(CMAKE_SWIG_FLAGS -c++ -threads)
+message(STATUS "CMAKE_SWIG_FLAGS=${CMAKE_SWIG_FLAGS}")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(SoapySDR3 python ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 674f300..92555b1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -19,3 +19,7 @@ add_test(TestTimeConversion TestTimeConversion)
add_executable(TestFormatParser TestFormatParser.cpp)
target_link_libraries(TestFormatParser SoapySDR)
add_test(TestFormatParser TestFormatParser)
+
+add_executable(TestKwargsMarkup TestKwargsMarkup.cpp)
+target_link_libraries(TestKwargsMarkup SoapySDR)
+add_test(TestKwargsMarkup TestKwargsMarkup)
diff --git a/tests/TestKwargsMarkup.cpp b/tests/TestKwargsMarkup.cpp
new file mode 100644
index 0000000..ab68cb0
--- /dev/null
+++ b/tests/TestKwargsMarkup.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) 2016-2016 Josh Blum
+// SPDX-License-Identifier: BSL-1.0
+
+#include <SoapySDR/Types.hpp>
+#include <cstdlib>
+#include <cstdio>
+
+bool checkArgsInLhs__(const SoapySDR::Kwargs &lhs, const SoapySDR::Kwargs &rhs)
+{
+ const auto strLhs = SoapySDR::KwargsToString(lhs);
+ const auto strRhs = SoapySDR::KwargsToString(rhs);
+ for (const auto &pair : lhs)
+ {
+ if (rhs.count(pair.first) == 0)
+ {
+ printf("FAIL: {%s}[%s] not found in {%s}\n",
+ strLhs.c_str(), pair.first.c_str(), strRhs.c_str());
+ return false;
+ }
+ if (pair.second != rhs.at(pair.first))
+ {
+ printf("FAIL: {%s}[%s] != {%s}[%s]\n",
+ strLhs.c_str(), pair.first.c_str(), strRhs.c_str(), pair.first.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+int main(void)
+{
+ #define checkArgsEq(lhs, rhs) \
+ { \
+ printf("Test line %d\n", __LINE__); \
+ if (not checkArgsInLhs__(lhs, rhs)) return EXIT_FAILURE; \
+ if (not checkArgsInLhs__(rhs, lhs)) return EXIT_FAILURE; \
+ }
+
+ //string to args - empty string
+ checkArgsEq(SoapySDR::KwargsFromString(""), SoapySDR::Kwargs());
+ checkArgsEq(SoapySDR::KwargsFromString(" "), SoapySDR::Kwargs());
+
+ //single keyword
+ SoapySDR::Kwargs args0;
+ args0["Foo"] = "Bar";
+ checkArgsEq(SoapySDR::KwargsFromString("Foo=Bar"), args0);
+ checkArgsEq(SoapySDR::KwargsFromString(" Foo = Bar "), args0);
+ checkArgsEq(SoapySDR::KwargsFromString(" Foo = Bar, "), args0);
+
+ //two keywords
+ SoapySDR::Kwargs args1;
+ args1["Foo"] = "Bar";
+ args1["Baz"] = "123";
+ checkArgsEq(SoapySDR::KwargsFromString("Foo=Bar, Baz=123"), args1);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz=123,Foo = Bar "), args1);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz=123,Foo = Bar , "), args1);
+
+ //empty value
+ SoapySDR::Kwargs args2;
+ args2["Foo"] = "Bar";
+ args2["Baz"] = "";
+ checkArgsEq(SoapySDR::KwargsFromString("Foo=Bar, Baz="), args2);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz=,Foo = Bar "), args2);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz= ,Foo = Bar , "), args2);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz ,Foo = Bar"), args2);
+ checkArgsEq(SoapySDR::KwargsFromString("Baz,Foo = Bar"), args2);
+
+ //loopback arg to markup to arg
+ checkArgsEq(SoapySDR::KwargsFromString(SoapySDR::KwargsToString(SoapySDR::Kwargs())), SoapySDR::Kwargs());
+ checkArgsEq(SoapySDR::KwargsFromString(SoapySDR::KwargsToString(args0)), args0);
+ checkArgsEq(SoapySDR::KwargsFromString(SoapySDR::KwargsToString(args1)), args1);
+ checkArgsEq(SoapySDR::KwargsFromString(SoapySDR::KwargsToString(args2)), args2);
+
+ printf("DONE!\n");
+ return EXIT_SUCCESS;
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/soapysdr.git
More information about the pkg-hamradio-commits
mailing list