aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2018-01-18 08:01:45 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2018-01-18 08:26:21 +0100
commitef1085cd66e347cfbd6ff689f5e0c9a940ca781c (patch)
treeabce7f875944d9594495374a9cada4e60d43ff16
downloadSoapyDummy-ef1085cd66e347cfbd6ff689f5e0c9a940ca781c.tar.gz
SoapyDummy-ef1085cd66e347cfbd6ff689f5e0c9a940ca781c.tar.bz2
SoapyDummy-ef1085cd66e347cfbd6ff689f5e0c9a940ca781c.zip
Add initial dummy driver code
-rw-r--r--CMakeLists.txt27
-rw-r--r--Dummy_Registration.cpp47
-rw-r--r--Dummy_Session.cpp52
-rw-r--r--Dummy_Settings.cpp302
-rw-r--r--Dummy_Streaming.cpp296
-rw-r--r--LICENSE22
-rw-r--r--README.md36
-rw-r--r--SoapyDummy.hpp207
-rw-r--r--self_test.py81
9 files changed, 1070 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..6010eb7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,27 @@
+########################################################################
+# CMake project for building the Soapy Dummy driver
+########################################################################
+
+cmake_minimum_required(VERSION 2.8.7)
+project(SoapyDummy CXX)
+set(CMAKE_BUILD_TYPE "Debug")
+
+find_package(SoapySDR "0.4.0" NO_MODULE)
+ if (NOT SoapySDR_FOUND)
+ message(FATAL_ERROR "Soapy SDR development files not found...")
+ endif ()
+
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-unused-parameter")
+
+SOAPY_SDR_MODULE_UTIL(
+ TARGET DummySupport
+ SOURCES
+ Dummy_Registration.cpp
+ Dummy_Settings.cpp
+ Dummy_Streaming.cpp
+ Dummy_Session.cpp
+)
diff --git a/Dummy_Registration.cpp b/Dummy_Registration.cpp
new file mode 100644
index 0000000..7e9081c
--- /dev/null
+++ b/Dummy_Registration.cpp
@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SoapyDummy.hpp"
+#include <SoapySDR/Registry.hpp>
+
+static std::vector<SoapySDR::Kwargs> find_Dummy(const SoapySDR::Kwargs &args)
+{
+ SoapyDummySession sess;
+
+ std::vector<SoapySDR::Kwargs> results;
+
+ SoapySDR::Kwargs options;
+ options["device"] = "dummy0";
+ options["version"] = "1";
+ results.push_back(options);
+
+ return results;
+}
+
+static SoapySDR::Device *make_Dummy(const SoapySDR::Kwargs &args)
+{
+ return new SoapyDummy(args);
+}
+
+static SoapySDR::Registry register_dummy("dummy", &find_Dummy, &make_Dummy, SOAPY_SDR_ABI_VERSION);
diff --git a/Dummy_Session.cpp b/Dummy_Session.cpp
new file mode 100644
index 0000000..1732149
--- /dev/null
+++ b/Dummy_Session.cpp
@@ -0,0 +1,52 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SoapyDummy.hpp"
+#include <SoapySDR/Logger.hpp>
+#include <mutex>
+#include <cstddef>
+
+static std::mutex sessionMutex;
+static size_t sessionCount = 0;
+
+SoapyDummySession::SoapyDummySession(void)
+{
+ std::lock_guard<std::mutex> lock(sessionMutex);
+
+ if (sessionCount == 0) {
+ SoapySDR::logf(SOAPY_SDR_INFO, "Opening dummy session");
+ }
+ sessionCount++;
+}
+
+SoapyDummySession::~SoapyDummySession(void)
+{
+ std::lock_guard<std::mutex> lock(sessionMutex);
+
+ sessionCount--;
+ if (sessionCount == 0)
+ {
+ SoapySDR::logf(SOAPY_SDR_INFO, "Last dummy session closed");
+ }
+}
diff --git a/Dummy_Settings.cpp b/Dummy_Settings.cpp
new file mode 100644
index 0000000..acf8614
--- /dev/null
+++ b/Dummy_Settings.cpp
@@ -0,0 +1,302 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SoapyDummy.hpp"
+
+
+SoapyDummy::SoapyDummy( const SoapySDR::Kwargs &args )
+{
+}
+
+SoapyDummy::~SoapyDummy( void )
+{
+}
+
+/*******************************************************************
+ * Identification API
+ ******************************************************************/
+std::string SoapyDummy::getDriverKey( void ) const
+{
+ return("Dummy");
+}
+
+std::string SoapyDummy::getHardwareKey( void ) const
+{
+ return "DummyHWKey";
+}
+
+SoapySDR::Kwargs SoapyDummy::getHardwareInfo( void ) const
+{
+ SoapySDR::Kwargs info;
+ info["version"] = "1";
+ info["clock source"] = "fictious";
+ return info;
+}
+
+/*******************************************************************
+ * Channels API
+ ******************************************************************/
+size_t SoapyDummy::getNumChannels( const int dir ) const
+{
+ return 1;
+}
+
+
+bool SoapyDummy::getFullDuplex( const int direction, const size_t channel ) const
+{
+ return true;
+}
+
+/*******************************************************************
+ * Settings API
+ ******************************************************************/
+SoapySDR::ArgInfoList SoapyDummy::getSettingInfo(void) const
+{
+ SoapySDR::ArgInfoList setArgs;
+
+ /* example setting from hackrf
+ SoapySDR::ArgInfo biastxArg;
+ biastxArg.key="bias_tx";
+ biastxArg.value="false";
+ biastxArg.name="Antenna Bias";
+ biastxArg.description="Antenna port power control.";
+ biastxArg.type=SoapySDR::ArgInfo::BOOL;
+ setArgs.push_back(biastxArg);
+ */
+
+ return setArgs;
+}
+
+void SoapyDummy::writeSetting(const std::string &key, const std::string &value)
+{
+ /*
+ if(key=="bias_tx"){
+ std::lock_guard<std::mutex> lock(_device_mutex);
+ _tx_stream.bias=(value=="true") ? true : false;
+ int ret=hackrf_set_antenna_enable(_dev,_tx_stream.bias);
+ if(ret!=HACKRF_SUCCESS){
+
+ SoapySDR_logf(SOAPY_SDR_INFO,"Failed to apply antenna bias voltage");
+
+ }
+ }
+ */
+}
+
+std::string SoapyDummy::readSetting(const std::string &key) const
+{
+ /*
+ if (key == "bias_tx") {
+ return _tx_stream.bias?"true":"false";
+ }
+ */
+ return "";
+}
+
+/*******************************************************************
+ * Antenna API
+ ******************************************************************/
+std::vector<std::string> SoapyDummy::listAntennas( const int direction, const size_t channel ) const
+{
+ std::vector<std::string> options;
+ if ( direction == SOAPY_SDR_RX ) {
+ options.push_back("RX");
+ }
+ else {
+ options.push_back("TX");
+ }
+ return options;
+}
+
+void SoapyDummy::setAntenna( const int direction, const size_t channel, const std::string &name )
+{
+ /* TODO delete this function or throw if name != RX... */
+}
+
+std::string SoapyDummy::getAntenna( const int direction, const size_t channel ) const
+{
+ if ( direction == SOAPY_SDR_RX ) {
+ return "RX";
+ }
+ else {
+ return "TX";
+ }
+}
+
+/*******************************************************************
+ * Frontend corrections API
+ ******************************************************************/
+bool SoapyDummy::hasDCOffsetMode( const int direction, const size_t channel ) const
+{
+ return false;
+}
+
+
+/*******************************************************************
+ * Gain API
+ ******************************************************************/
+std::vector<std::string> SoapyDummy::listGains( const int direction, const size_t channel ) const
+{
+ std::vector<std::string> options;
+ options.push_back( "GAIN" );
+
+ return options;
+}
+
+
+void SoapyDummy::setGainMode( const int direction, const size_t channel, const bool automatic )
+{
+ /* enable AGC if the hardware supports it, or remove this function */
+}
+
+
+bool SoapyDummy::getGainMode( const int direction, const size_t channel ) const
+{
+ return false;
+}
+
+
+void SoapyDummy::setGain( const int direction, const size_t channel, const double value )
+{
+ if ( direction == SOAPY_SDR_RX ) {
+ }
+ else if ( direction == SOAPY_SDR_TX ) {
+ }
+}
+
+void SoapyDummy::setGain( const int direction, const size_t channel, const std::string &name, const double value )
+{
+
+}
+
+
+double SoapyDummy::getGain( const int direction, const size_t channel, const std::string &name ) const
+{
+ return 10.0;
+}
+
+
+SoapySDR::Range SoapyDummy::getGainRange( const int direction, const size_t channel, const std::string &name ) const
+{
+ if (name == "GAIN") {
+ return(SoapySDR::Range( 0, 60 ) );
+ }
+ return(SoapySDR::Range( 0, 0 ) );
+}
+
+
+/*******************************************************************
+ * Frequency API
+ ******************************************************************/
+void SoapyDummy::setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args )
+{
+ if ( name != "RF" ) {
+ throw std::runtime_error( "setFrequency(" + name + ") unknown name" );
+ }
+
+ if (direction==SOAPY_SDR_RX){
+ m_frequency = frequency;
+ }
+ else if (direction==SOAPY_SDR_TX){
+ m_frequency = frequency;
+ }
+}
+
+
+double SoapyDummy::getFrequency( const int direction, const size_t channel, const std::string &name ) const
+{
+ if ( name != "RF" ) {
+ throw std::runtime_error( "getFrequency(" + name + ") unknown name" );
+ }
+
+ double freq = 0.0;
+
+ if (direction==SOAPY_SDR_RX){
+ freq = m_frequency;
+ }
+ else if (direction==SOAPY_SDR_TX){
+ freq = m_frequency;
+ }
+ return freq;
+}
+
+SoapySDR::ArgInfoList SoapyDummy::getFrequencyArgsInfo(const int direction, const size_t channel) const
+{
+ SoapySDR::ArgInfoList freqArgs;
+ return freqArgs;
+}
+
+std::vector<std::string> SoapyDummy::listFrequencies( const int direction, const size_t channel ) const
+{
+ std::vector<std::string> names;
+ names.push_back( "RF" );
+ return names;
+}
+
+SoapySDR::RangeList SoapyDummy::getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const
+{
+ if ( name != "RF" )
+ throw std::runtime_error( "getFrequencyRange(" + name + ") unknown name" );
+ return(SoapySDR::RangeList( 1, SoapySDR::Range( 0, 7250000000ull ) ) );
+}
+
+/*******************************************************************
+ * Sample Rate API
+ ******************************************************************/
+void SoapyDummy::setSampleRate( const int direction, const size_t channel, const double rate )
+{
+ m_samplerate = rate;
+}
+
+double SoapyDummy::getSampleRate( const int direction, const size_t channel ) const
+{
+ return m_samplerate;
+}
+
+std::vector<double> SoapyDummy::listSampleRates( const int direction, const size_t channel ) const
+{
+ std::vector<double> options;
+ for ( double r = 1e6; r <= 20e6; r += 1e6 ) {
+ options.push_back( r );
+ }
+ return options;
+}
+
+
+void SoapyDummy::setBandwidth( const int direction, const size_t channel, const double bw )
+{
+}
+
+
+double SoapyDummy::getBandwidth( const int direction, const size_t channel ) const
+{
+ return 8000000;
+}
+
+std::vector<double> SoapyDummy::listBandwidths( const int direction, const size_t channel ) const
+{
+ std::vector<double> options;
+ options.push_back( 8000000 );
+ return(options);
+}
diff --git a/Dummy_Streaming.cpp b/Dummy_Streaming.cpp
new file mode 100644
index 0000000..493800d
--- /dev/null
+++ b/Dummy_Streaming.cpp
@@ -0,0 +1,296 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SoapyDummy.hpp"
+#include <SoapySDR/Logger.hpp>
+#include <SoapySDR/Formats.hpp>
+#include <chrono>
+#include <thread>
+#include <algorithm>
+
+std::vector<std::string> SoapyDummy::getStreamFormats(const int direction, const size_t channel) const
+{
+ std::vector<std::string> formats;
+
+ formats.push_back(SOAPY_SDR_CS8);
+ formats.push_back(SOAPY_SDR_CS16);
+ formats.push_back(SOAPY_SDR_CF32);
+ formats.push_back(SOAPY_SDR_CF64);
+
+ return formats;
+}
+
+std::string SoapyDummy::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
+{
+ fullScale = 1.0;
+ return SOAPY_SDR_CF32;
+}
+
+SoapySDR::ArgInfoList SoapyDummy::getStreamArgsInfo(const int direction, const size_t channel) const
+{
+ SoapySDR::ArgInfoList streamArgs;
+
+ SoapySDR::ArgInfo buffersArg;
+ buffersArg.key="buffers";
+ buffersArg.value = std::to_string(1);
+ buffersArg.name = "Buffer Count";
+ buffersArg.description = "Number of buffers per read.";
+ buffersArg.units = "buffers";
+ buffersArg.type = SoapySDR::ArgInfo::INT;
+ streamArgs.push_back(buffersArg);
+
+ return streamArgs;
+}
+
+SoapySDR::Stream* SoapyDummy::setupStream(
+ const int direction,
+ const std::string &format,
+ const std::vector<size_t> &channels,
+ const SoapySDR::Kwargs &args )
+{
+ if ( channels.size() > 1 or( channels.size() > 0 and channels.at( 0 ) != 0 ) ) {
+ throw std::runtime_error( "setupStream invalid channel selection" );
+ }
+
+ if(direction==SOAPY_SDR_RX){
+
+ if ( format == SOAPY_SDR_CS8 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
+ }else if ( format == SOAPY_SDR_CS16 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
+ }else if ( format == SOAPY_SDR_CF32 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
+ }else if(format==SOAPY_SDR_CF64){
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
+ }else throw std::runtime_error( "setupStream invalid format " + format );
+
+ return RX_STREAM;
+ } else if(direction==SOAPY_SDR_TX){
+
+ if ( format == SOAPY_SDR_CS8 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
+ }else if ( format == SOAPY_SDR_CS16 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
+ }else if ( format == SOAPY_SDR_CF32 )
+ {
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
+ }else if(format==SOAPY_SDR_CF64){
+ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
+ }else throw std::runtime_error( "setupStream invalid format " + format );
+
+ return TX_STREAM;
+ }
+ else {
+ throw std::runtime_error("Invalid direction");
+ }
+}
+
+void SoapyDummy::closeStream( SoapySDR::Stream *stream )
+{
+ if (stream == RX_STREAM) {
+ } else if (stream == TX_STREAM) {
+ }
+}
+
+
+size_t SoapyDummy::getStreamMTU( SoapySDR::Stream *stream ) const
+{
+ if(stream == RX_STREAM){
+ return m_rxstream.mtu;
+ } else if(stream == TX_STREAM){
+ return m_txstream.mtu;
+ } else {
+ throw std::runtime_error("Invalid stream");
+ }
+}
+
+int SoapyDummy::activateStream(
+ SoapySDR::Stream *stream,
+ const int flags,
+ const long long timeNs,
+ const size_t numElems )
+{
+ if (stream == RX_STREAM) {
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Start RX");
+ }
+ else if (stream == TX_STREAM) {
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Start TX");
+ }
+
+ return 0;
+}
+
+
+int SoapyDummy::deactivateStream(
+ SoapySDR::Stream *stream,
+ const int flags,
+ const long long timeNs )
+{
+
+ if (stream == RX_STREAM) {
+ }
+ else if (stream == TX_STREAM) {
+ }
+ return 0;
+}
+
+
+int SoapyDummy::readStream(
+ SoapySDR::Stream *stream,
+ void * const *buffs,
+ const size_t numElems,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs )
+{
+ if (stream != RX_STREAM){
+ return SOAPY_SDR_NOT_SUPPORTED;
+ }
+
+ size_t returnedElems = std::min(numElems,this->getStreamMTU(stream));
+ return returnedElems;
+}
+
+int SoapyDummy::writeStream(
+ SoapySDR::Stream *stream,
+ const void * const *buffs,
+ const size_t numElems,
+ int &flags,
+ const long long timeNs,
+ const long timeoutUs )
+{
+ if (stream != TX_STREAM){
+ return SOAPY_SDR_NOT_SUPPORTED;
+ }
+
+ size_t returnedElems = std::min(numElems,this->getStreamMTU(stream));
+
+ return returnedElems;
+}
+
+
+int SoapyDummy::readStreamStatus(
+ SoapySDR::Stream *stream,
+ size_t &chanMask,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs
+ ){
+
+ if(stream != TX_STREAM){
+ return SOAPY_SDR_NOT_SUPPORTED;
+ }
+
+ return SOAPY_SDR_TIMEOUT;
+}
+
+int SoapyDummy::acquireReadBuffer(
+ SoapySDR::Stream *stream,
+ size_t &handle,
+ const void **buffs,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs)
+{
+ if (stream != RX_STREAM){
+ return SOAPY_SDR_NOT_SUPPORTED;
+ }
+
+ return this->getStreamMTU(stream);
+}
+
+void SoapyDummy::releaseReadBuffer(
+ SoapySDR::Stream *stream,
+ const size_t handle)
+{
+ if(stream != RX_STREAM){
+ throw std::runtime_error("Invalid stream");
+ }
+}
+
+int SoapyDummy::acquireWriteBuffer(
+ SoapySDR::Stream *stream,
+ size_t &handle,
+ void **buffs,
+ const long timeoutUs)
+{
+
+ if(stream != TX_STREAM){
+ return SOAPY_SDR_NOT_SUPPORTED;
+ }
+
+ return this->getStreamMTU(stream);
+}
+
+void SoapyDummy::releaseWriteBuffer(
+ SoapySDR::Stream *stream,
+ const size_t handle,
+ const size_t numElems,
+ int &flags,
+ const long long timeNs)
+{
+ if (stream == TX_STREAM) {
+ }
+ else {
+ throw std::runtime_error("Invalid stream");
+ }
+}
+
+size_t SoapyDummy::getNumDirectAccessBuffers(
+ SoapySDR::Stream *stream)
+{
+ if (stream == RX_STREAM) {
+ return m_rxstream.buf_num;
+ }
+ else if(stream == TX_STREAM){
+ return m_rxstream.buf_num;
+ }
+ else {
+ throw std::runtime_error("Invalid stream");
+ }
+}
+
+int SoapyDummy::getDirectAccessBufferAddrs(
+ SoapySDR::Stream *stream,
+ const size_t handle,
+ void **buffs)
+{
+
+ if (stream == RX_STREAM) {
+ buffs[0]=(void *)m_rxstream.buf;
+ }
+ else if (stream == TX_STREAM) {
+ buffs[0]=(void *)m_txstream.buf;
+ }
+ else {
+ throw std::runtime_error("Invalid stream");
+ }
+
+ return 0;
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ba44f9e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Matthias P. Braendli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d778870
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+SoapySDR Dummy driver
+=====================
+
+This is a dummy driver for SoapySDR.
+
+Dependencies
+------------
+
+* SoapySDR - https://github.com/pothosware/SoapySDR/wiki
+
+
+Licensing information
+---------------------
+
+The MIT License (MIT)
+
+Copyright (c) 2018 Matthias P. Braendli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/SoapyDummy.hpp b/SoapyDummy.hpp
new file mode 100644
index 0000000..e1ca79a
--- /dev/null
+++ b/SoapyDummy.hpp
@@ -0,0 +1,207 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+#include <string.h>
+#include <mutex>
+#include <condition_variable>
+#include <SoapySDR/Device.hpp>
+#include <SoapySDR/Logger.hpp>
+
+class SoapyDummySession
+{
+ public:
+ SoapyDummySession(void);
+ ~SoapyDummySession(void);
+};
+
+class SoapyDummy : public SoapySDR::Device
+{
+ public:
+ SoapyDummy( const SoapySDR::Kwargs & args );
+ SoapyDummy(const SoapyDummy& other) = delete;
+ SoapyDummy& operator=(const SoapyDummy& other) = delete;
+ ~SoapyDummy( void );
+
+ /*******************************************************************
+ * Identification API
+ ******************************************************************/
+ std::string getDriverKey( void ) const;
+ std::string getHardwareKey( void ) const;
+ SoapySDR::Kwargs getHardwareInfo( void ) const;
+
+ /*******************************************************************
+ * Channels API
+ ******************************************************************/
+ size_t getNumChannels( const int ) const;
+ bool getFullDuplex( const int direction, const size_t channel ) const;
+
+ /*******************************************************************
+ * Stream API
+ ******************************************************************/
+ std::vector<std::string> getStreamFormats(const int direction, const size_t channel) const;
+ std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const;
+ SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const;
+ SoapySDR::Stream *setupStream(
+ const int direction,
+ const std::string &format,
+ const std::vector<size_t> &channels = std::vector<size_t>(),
+ const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );
+
+ void closeStream( SoapySDR::Stream *stream );
+ size_t getStreamMTU( SoapySDR::Stream *stream ) const;
+ int activateStream(
+ SoapySDR::Stream *stream,
+ const int flags = 0,
+ const long long timeNs = 0,
+ const size_t numElems = 0 );
+
+ int deactivateStream(
+ SoapySDR::Stream *stream,
+ const int flags = 0,
+ const long long timeNs = 0 );
+
+ int readStream(
+ SoapySDR::Stream *stream,
+ void * const *buffs,
+ const size_t numElems,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs = 100000 );
+
+ int writeStream(
+ SoapySDR::Stream *stream,
+ const void * const *buffs,
+ const size_t numElems,
+ int &flags,
+ const long long timeNs = 0,
+ const long timeoutUs = 100000);
+
+ int readStreamStatus(
+ SoapySDR::Stream *stream,
+ size_t &chanMask,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs
+ );
+
+ int acquireReadBuffer(
+ SoapySDR::Stream *stream,
+ size_t &handle,
+ const void **buffs,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs = 100000);
+
+ void releaseReadBuffer(
+ SoapySDR::Stream *stream,
+ const size_t handle);
+
+ int acquireWriteBuffer(
+ SoapySDR::Stream *stream,
+ size_t &handle,
+ void **buffs,
+ const long timeoutUs = 100000);
+
+ void releaseWriteBuffer(
+ SoapySDR::Stream *stream,
+ const size_t handle,
+ const size_t numElems,
+ int &flags,
+ const long long timeNs = 0);
+
+ size_t getNumDirectAccessBuffers(SoapySDR::Stream *stream);
+ int getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs);
+
+ /*******************************************************************
+ * Settings API
+ ******************************************************************/
+ SoapySDR::ArgInfoList getSettingInfo(void) const;
+ void writeSetting(const std::string &key, const std::string &value);
+ std::string readSetting(const std::string &key) const;
+
+ /*******************************************************************
+ * Antenna API
+ ******************************************************************/
+ std::vector<std::string> listAntennas( const int direction, const size_t channel ) const;
+ void setAntenna( const int direction, const size_t channel, const std::string &name );
+ std::string getAntenna( const int direction, const size_t channel ) const;
+
+ /*******************************************************************
+ * Frontend corrections API
+ ******************************************************************/
+ bool hasDCOffsetMode( const int direction, const size_t channel ) const;
+
+ /*******************************************************************
+ * Gain API
+ ******************************************************************/
+ std::vector<std::string> listGains( 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;
+ 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 std::string &name ) const;
+ SoapySDR::Range getGainRange( const int direction, const size_t channel, const std::string &name ) const;
+
+ /*******************************************************************
+ * Frequency API
+ ******************************************************************/
+ void setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );
+ double getFrequency( const int direction, const size_t channel, const std::string &name ) const;
+ SoapySDR::ArgInfoList getFrequencyArgsInfo(const int direction, const size_t channel) const;
+ std::vector<std::string> listFrequencies( const int direction, const size_t channel ) const;
+ SoapySDR::RangeList getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const;
+
+ /*******************************************************************
+ * Sample Rate API
+ ******************************************************************/
+ void setSampleRate( const int direction, const size_t channel, const double rate );
+ double getSampleRate( const int direction, const size_t channel ) const;
+ std::vector<double> listSampleRates( const int direction, const size_t channel ) const;
+ void setBandwidth( const int direction, const size_t channel, const double bw );
+ double getBandwidth( const int direction, const size_t channel ) const;
+ std::vector<double> listBandwidths( const int direction, const size_t channel ) const;
+
+ /*******************************************************************
+ * Dummy callback
+ ******************************************************************/
+ int dummy_tx_callback( int8_t *buffer, int32_t length );
+ int dummy_rx_callback( int8_t *buffer, int32_t length );
+
+ private:
+ struct DummyStream {
+ size_t mtu = 1024;
+ size_t buf_num = 1;
+ std::complex<float> buf[1024];
+ };
+
+ DummyStream m_rxstream;
+ DummyStream m_txstream;
+ SoapySDR::Stream* const TX_STREAM = (SoapySDR::Stream*) 0x1;
+ SoapySDR::Stream* const RX_STREAM = (SoapySDR::Stream*) 0x2;
+
+ SoapyDummySession m_session;
+ double m_samplerate = 0;
+ double m_frequency = 0;
+};
diff --git a/self_test.py b/self_test.py
new file mode 100644
index 0000000..e18a933
--- /dev/null
+++ b/self_test.py
@@ -0,0 +1,81 @@
+import SoapySDR
+from SoapySDR import * #SOAPY_SDR_* constants
+import numpy as np
+import time
+
+if __name__ == "__main__":
+ dummy = SoapySDR.Device(dict(driver="dummy"))
+ print(dummy)
+
+ dummy.setSampleRate(SOAPY_SDR_RX, 0, 8e6)
+ dummy.setSampleRate(SOAPY_SDR_TX, 0, 8e6)
+
+ """
+ for i in range(5):
+ print(" Make rx stream #%d"%i)
+ rxStream = dummy.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0])
+ for j in range(5):
+ numSampsTotal = 10000
+ print(" Activate, get %d samples, Deactivate #%d"%(numSampsTotal, j))
+ dummy.activateStream(rxStream)
+ buff = np.array([0]*1024, np.complex64)
+ while numSampsTotal > 0:
+ sr = dummy.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6))
+ #print sr
+ assert(sr.ret > 0)
+ numSampsTotal -= sr.ret
+ dummy.deactivateStream(rxStream)
+ dummy.closeStream(rxStream)
+
+ for i in range(5):
+ print(" Make tx stream #%d"%i)
+ txStream = dummy.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0])
+ for j in range(5):
+ numSampsTotal = 10000
+ print(" Activate, send %d samples, Deactivate #%d"%(numSampsTotal, j))
+ dummy.activateStream(txStream)
+ buff = np.array([0]*1024, np.complex64)
+ while numSampsTotal != 0:
+ size = min(buff.size, numSampsTotal)
+ sr = dummy.writeStream(txStream, [buff], size)
+ #print sr
+ if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal))
+ assert(sr.ret > 0)
+ numSampsTotal -= sr.ret
+ dummy.deactivateStream(txStream)
+ dummy.closeStream(txStream)
+ """
+
+ ####################################################################
+ #setup both streams at once
+ ####################################################################
+ rxStream = dummy.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0])
+ txStream = dummy.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0])
+
+ dummy.activateStream(rxStream)
+ dummy.activateStream(txStream)
+
+ numSampsTotal = 10000
+ dummy.activateStream(rxStream)
+ buff = np.array([0]*1024, np.complex64)
+ while numSampsTotal > 0:
+ sr = dummy.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6))
+ #print(sr)
+ assert(sr.ret > 0)
+ numSampsTotal -= sr.ret
+
+ numSampsTotal = 10000
+ buff = np.array([0]*1024, np.complex64)
+ while numSampsTotal != 0:
+ size = min(buff.size, numSampsTotal)
+ sr = dummy.writeStream(txStream, [buff], size)
+ #print(sr)
+ if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal))
+ assert(sr.ret > 0)
+ numSampsTotal -= sr.ret
+
+ dummy.deactivateStream(rxStream)
+ dummy.deactivateStream(txStream)
+
+ dummy.closeStream(rxStream)
+ dummy.closeStream(txStream)