[hamradio-commits] [soapyremote] 01/09: New upstream version 0.4.2
Andreas E. Bombe
aeb at moszumanska.debian.org
Fri Aug 11 19:14:47 UTC 2017
This is an automated email from the git hooks/post-receive script.
aeb pushed a commit to branch master
in repository soapyremote.
commit be3e1030a579d1bd57678597ffe2c970b5fcd78b
Author: Andreas Bombe <aeb at debian.org>
Date: Mon Aug 7 17:13:20 2017 -0400
New upstream version 0.4.2
---
Changelog.txt | 29 +++
README.md | 2 +-
client/ClientStreamData.cpp | 118 +++++++++++-
client/ClientStreamData.hpp | 5 +-
client/LogAcceptor.cpp | 14 +-
client/Registration.cpp | 15 +-
client/Settings.cpp | 104 +++++++++-
client/SoapyClient.hpp | 19 +-
client/Streaming.cpp | 122 ++++++++----
common/CMakeLists.txt | 1 +
common/SoapyRPCPacker.cpp | 18 +-
common/SoapyRPCPacker.hpp | 5 +-
common/SoapyRPCSocket.cpp | 83 +++++++-
common/SoapyRPCSocket.hpp | 11 +-
common/SoapyRPCUnpacker.cpp | 51 ++++-
common/SoapyRPCUnpacker.hpp | 11 +-
common/SoapyRemoteDefs.hpp | 15 +-
common/SoapySocketDefs.in.hpp | 11 +-
common/SoapyStreamEndpoint.cpp | 45 ++++-
common/SoapyStreamEndpoint.hpp | 4 +-
debian/changelog | 20 +-
debian/control | 6 +-
debian/copyright | 2 +-
debian/soapysdr-server.install | 3 +-
debian/soapysdr-server.postrm | 13 ++
debian/soapysdr-server.prerm | 3 +-
...e.install => soapysdr0.6-module-remote.install} | 0
server/ClientHandler.cpp | 209 +++++++++++++++++----
server/ServerStreamData.cpp | 20 +-
server/ServerStreamData.hpp | 7 +-
system/SoapySDRServer.service.in | 2 +
31 files changed, 836 insertions(+), 132 deletions(-)
diff --git a/Changelog.txt b/Changelog.txt
index fdc4051..ef099b7 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,32 @@
+Release 0.4.2 (2017-07-31)
+==========================
+
+- Fixed timeout problem in log acceptor receiver loop
+- Added server check for slow calls and longer timeout
+ - This also resolves timeout errors for lengthy calls
+- Added network-online.target for systemd service script
+
+Release 0.4.1 (2017-06-08)
+==========================
+
+- Added timeout for logger connect and control unpacker
+- Fixed error log formatting in the client log acceptor
+
+Release 0.4.0 (2017-04-29)
+==========================
+
+- Added support for frequency corrections for fine adjustments
+- Added support forgetSampleRateRange() for continuous ranges
+- Added support for CF32 local format with CS12 remote format
+- Added support for CS16 local format with CS12 remote format
+- Added support for CS16 local format with CS8 remote format
+- readStream thread support for SOAPY_SDR_END_ABRUPT flag
+- readStream thread apply second SOAPY_SDR_END_BURST flag
+- Added timeout to socket connect and factory calls
+- Support range with step size (backwards compatible)
+- Added tcp support for streaming via remote:prot=tcp
+- Support for bulk register read/write interface APIs
+
Release 0.3.2 (2016-12-04)
==========================
diff --git a/README.md b/README.md
index 6c16ff5..f45107a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Use any Soapy SDR remotely
-##Build Status
+## Build Status
- Travis: [](https://travis-ci.org/pothosware/SoapyRemote)
diff --git a/client/ClientStreamData.cpp b/client/ClientStreamData.cpp
index 7f46170..dca1ae7 100644
--- a/client/ClientStreamData.cpp
+++ b/client/ClientStreamData.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "ClientStreamData.hpp"
@@ -57,6 +57,65 @@ void ClientStreamData::convertRecvBuffs(void * const *buffs, const size_t numEle
break;
///////////////////////////
+ case CONVERT_CF32_CS12:
+ ///////////////////////////
+ {
+ const float scale = float(1.0/scaleFactor);
+ for (size_t i = 0; i < recvBuffs.size(); i++)
+ {
+ auto in = (uint8_t *)recvBuffs[i];
+ auto out = (float *)buffs[i];
+ for (size_t j = 0; j < numElems; j++)
+ {
+ uint16_t part0 = uint16_t(*(in++));
+ uint16_t part1 = uint16_t(*(in++));
+ uint16_t part2 = uint16_t(*(in++));
+ int16_t i = int16_t((part1 << 12) | (part0 << 4));
+ int16_t q = int16_t((part2 << 8) | (part1 & 0xf0));
+ *(out++) = float(i)*scale;
+ *(out++) = float(q)*scale;
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
+ case CONVERT_CS16_CS12:
+ ///////////////////////////
+ {
+ for (size_t i = 0; i < recvBuffs.size(); i++)
+ {
+ auto in = (uint8_t *)recvBuffs[i];
+ auto out = (int16_t *)buffs[i];
+ for (size_t j = 0; j < numElems; j++)
+ {
+ uint16_t part0 = uint16_t(*(in++));
+ uint16_t part1 = uint16_t(*(in++));
+ uint16_t part2 = uint16_t(*(in++));
+ *(out++) = int16_t((part1 << 12) | (part0 << 4));
+ *(out++) = int16_t((part2 << 8) | (part1 & 0xf0));
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
+ case CONVERT_CS16_CS8:
+ ///////////////////////////
+ {
+ for (size_t i = 0; i < recvBuffs.size(); i++)
+ {
+ auto in = (int8_t *)recvBuffs[i];
+ auto out = (int16_t *)buffs[i];
+ for (size_t j = 0; j < numElems*2; j++)
+ {
+ out[j] = int16_t(in[j]);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
case CONVERT_CF32_CS8:
///////////////////////////
{
@@ -131,6 +190,63 @@ void ClientStreamData::convertSendBuffs(const void * const *buffs, const size_t
break;
///////////////////////////
+ case CONVERT_CF32_CS12:
+ ///////////////////////////
+ {
+ const float scale = float(scaleFactor);
+ for (size_t i = 0; i < sendBuffs.size(); i++)
+ {
+ auto in = (float *)buffs[i];
+ auto out = (uint8_t *)sendBuffs[i];
+ for (size_t j = 0; j < numElems; j++)
+ {
+ uint16_t i = uint16_t(*(in++)*scale);
+ uint16_t q = uint16_t(*(in++)*scale);
+ *(out++) = uint8_t(i >> 4);
+ *(out++) = uint8_t((q & 0xf0)|(i >> 12));
+ *(out++) = uint8_t(q >> 8);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
+ case CONVERT_CS16_CS12:
+ ///////////////////////////
+ {
+ for (size_t i = 0; i < sendBuffs.size(); i++)
+ {
+ auto in = (int16_t *)buffs[i];
+ auto out = (uint8_t *)sendBuffs[i];
+ for (size_t j = 0; j < numElems; j++)
+ {
+ uint16_t i = uint16_t(*(in++));
+ uint16_t q = uint16_t(*(in++));
+ *(out++) = uint8_t(i >> 4);
+ *(out++) = uint8_t((q & 0xf0)|(i >> 12));
+ *(out++) = uint8_t(q >> 8);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
+ case CONVERT_CS16_CS8:
+ ///////////////////////////
+ {
+ for (size_t i = 0; i < sendBuffs.size(); i++)
+ {
+ auto in = (int16_t *)buffs[i];
+ auto out = (int8_t *)sendBuffs[i];
+ for (size_t j = 0; j < numElems*2; j++)
+ {
+ out[j] = int8_t(in[j]);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////
case CONVERT_CF32_CS8:
///////////////////////////
{
diff --git a/client/ClientStreamData.hpp b/client/ClientStreamData.hpp
index 84c12e5..78ed190 100644
--- a/client/ClientStreamData.hpp
+++ b/client/ClientStreamData.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -12,6 +12,9 @@ enum ConvertTypes
{
CONVERT_MEMCPY,
CONVERT_CF32_CS16,
+ CONVERT_CF32_CS12,
+ CONVERT_CS16_CS12,
+ CONVERT_CS16_CS8,
CONVERT_CF32_CS8,
CONVERT_CF32_CU8,
};
diff --git a/client/LogAcceptor.cpp b/client/LogAcceptor.cpp
index 9ba2520..be25052 100644
--- a/client/LogAcceptor.cpp
+++ b/client/LogAcceptor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "LogAcceptor.hpp"
@@ -47,7 +47,9 @@ struct LogAcceptorThreadData
void LogAcceptorThreadData::activate(void)
{
client = SoapyRPCSocket();
- int ret = client.connect(url);
+ //specify a timeout on connect because the link may be lost
+ //when the thread attempts to re-establish a connection
+ int ret = client.connect(url, SOAPY_REMOTE_SOCKET_TIMEOUT_US);
if (ret != 0)
{
SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::connect() FAIL: %s", client.lastErrorMsg());
@@ -67,7 +69,7 @@ void LogAcceptorThreadData::activate(void)
}
catch (const std::exception &ex)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::reactivate() ", ex.what());
+ SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::activate() FAIL: %s", ex.what());
done = true;
}
}
@@ -88,7 +90,7 @@ void LogAcceptorThreadData::shutdown(void)
}
catch (const std::exception &ex)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::shutdown() ", ex.what());
+ SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::shutdown() FAIL: %s", ex.what());
}
//the thread will exit due to the requests above
@@ -106,7 +108,7 @@ void LogAcceptorThreadData::handlerLoop(void)
//loop while active to relay messages to logger
while (true)
{
- SoapyRPCUnpacker unpackerLogMsg(client);
+ SoapyRPCUnpacker unpackerLogMsg(client, true, -1/*no timeout*/);
if (unpackerLogMsg.done()) break; //got stop reply
char logLevel = 0;
std::string message;
@@ -117,7 +119,7 @@ void LogAcceptorThreadData::handlerLoop(void)
}
catch (const std::exception &ex)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::handlerLoop() ", ex.what());
+ SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyLogAcceptor::handlerLoop() FAIL: %s", ex.what());
}
done = true;
diff --git a/client/Registration.cpp b/client/Registration.cpp
index aa0dc5f..5b80619 100644
--- a/client/Registration.cpp
+++ b/client/Registration.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2016 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "SoapyClient.hpp"
@@ -11,6 +11,7 @@
#include <SoapySDR/Registry.hpp>
#include <SoapySDR/Logger.hpp>
#include <thread>
+#include <future>
/***********************************************************************
* Args translator for nested keywords
@@ -77,11 +78,19 @@ static std::vector<SoapySDR::Kwargs> findRemote(const SoapySDR::Kwargs &args)
const auto ipVerIt = args.find("remote:ipver");
if (ipVerIt != args.end()) ipVer = std::stoi(ipVerIt->second);
+ //spawn futures to connect to each remote
+ std::vector<std::future<SoapySDR::KwargsList>> futures;
for (const auto &url : SoapySSDPEndpoint::getInstance()->getServerURLs(ipVer))
{
auto argsWithURL = args;
argsWithURL["remote"] = url;
- const auto subResult = findRemote(argsWithURL);
+ futures.push_back(std::async(std::launch::async, &findRemote, argsWithURL));
+ }
+
+ //wait on all futures for results
+ for (auto &future : futures)
+ {
+ const auto subResult = future.get();
result.insert(result.end(), subResult.begin(), subResult.end());
}
@@ -98,7 +107,7 @@ static std::vector<SoapySDR::Kwargs> findRemote(const SoapySDR::Kwargs &args)
//try to connect to the remote server
SoapySocketSession sess;
SoapyRPCSocket s;
- int ret = s.connect(url.toString());
+ int ret = s.connect(url.toString(), SOAPY_REMOTE_SOCKET_TIMEOUT_US);
if (ret != 0)
{
SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyRemote::find() -- connect(%s) FAIL: %s", url.toString().c_str(), s.lastErrorMsg());
diff --git a/client/Settings.cpp b/client/Settings.cpp
index 3e1fd93..4264495 100644
--- a/client/Settings.cpp
+++ b/client/Settings.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
@@ -10,19 +10,16 @@
#include <SoapySDR/Logger.hpp>
#include <stdexcept>
-//lazy fix for the const call issue -- FIXME
-#define _mutex const_cast<std::mutex &>(_mutex)
-#define _sock const_cast<SoapyRPCSocket &>(_sock)
-
/*******************************************************************
* Constructor
******************************************************************/
SoapyRemoteDevice::SoapyRemoteDevice(const std::string &url, const SoapySDR::Kwargs &args):
- _logAcceptor(nullptr)
+ _logAcceptor(nullptr),
+ _defaultStreamProt("udp")
{
//try to connect to the remote server
- int ret = _sock.connect(url);
+ int ret = _sock.connect(url, SOAPY_REMOTE_SOCKET_TIMEOUT_US);
if (ret != 0)
{
throw std::runtime_error("SoapyRemoteDevice("+url+") -- connect FAIL: " + _sock.lastErrorMsg());
@@ -37,6 +34,10 @@ SoapyRemoteDevice::SoapyRemoteDevice(const std::string &url, const SoapySDR::Kwa
packer & args;
packer();
SoapyRPCUnpacker unpacker(_sock);
+
+ //default stream protocol specified in device args
+ const auto protIt = args.find("prot");
+ if (protIt != args.end()) _defaultStreamProt = protIt->second;
}
SoapyRemoteDevice::~SoapyRemoteDevice(void)
@@ -362,6 +363,49 @@ std::complex<double> SoapyRemoteDevice::getIQBalance(const int direction, const
return result;
}
+bool SoapyRemoteDevice::hasFrequencyCorrection(const int direction, const size_t channel) const
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ packer & SOAPY_REMOTE_HAS_FREQUENCY_CORRECTION;
+ packer & char(direction);
+ packer & int(channel);
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+ bool result;
+ unpacker & result;
+ return result;
+}
+
+void SoapyRemoteDevice::setFrequencyCorrection(const int direction, const size_t channel, const double value)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ packer & SOAPY_REMOTE_SET_FREQUENCY_CORRECTION;
+ packer & char(direction);
+ packer & int(channel);
+ packer & value;
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+}
+
+double SoapyRemoteDevice::getFrequencyCorrection(const int direction, const size_t channel) const
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ packer & SOAPY_REMOTE_GET_FREQUENCY_CORRECTION;
+ packer & char(direction);
+ packer & int(channel);
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+ double result;
+ unpacker & result;
+ return result;
+}
+
/*******************************************************************
* Gain API
******************************************************************/
@@ -685,6 +729,21 @@ std::vector<double> SoapyRemoteDevice::listSampleRates(const int direction, cons
return result;
}
+SoapySDR::RangeList SoapyRemoteDevice::getSampleRateRange(const int direction, const size_t channel) const
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ packer & SOAPY_REMOTE_GET_SAMPLE_RATE_RANGE;
+ packer & char(direction);
+ packer & int(channel);
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+ SoapySDR::RangeList result;
+ unpacker & result;
+ return result;
+}
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -1081,6 +1140,37 @@ unsigned SoapyRemoteDevice::readRegister(const unsigned addr) const
return unsigned(result);
}
+void SoapyRemoteDevice::writeRegisters(const std::string &name, const unsigned addr, const std::vector<unsigned> &value)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ std::vector<size_t> val (value.begin(), value.end());
+ packer & SOAPY_REMOTE_WRITE_REGISTERS;
+ packer & name;
+ packer & int(addr);
+ packer & val;
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+}
+
+std::vector<unsigned> SoapyRemoteDevice::readRegisters(const std::string &name, const unsigned addr, const size_t length) const
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+ SoapyRPCPacker packer(_sock);
+ packer & SOAPY_REMOTE_READ_REGISTERS;
+ packer & name;
+ packer & int(addr);
+ packer & int(length);
+ packer();
+
+ SoapyRPCUnpacker unpacker(_sock);
+ std::vector<size_t> result;
+ unpacker & result;
+ std::vector<unsigned> res (result.begin(), result.end());
+ return res;
+}
+
/*******************************************************************
* Settings API
******************************************************************/
diff --git a/client/SoapyClient.hpp b/client/SoapyClient.hpp
index 8e5eb62..0f24fe5 100644
--- a/client/SoapyClient.hpp
+++ b/client/SoapyClient.hpp
@@ -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
@@ -161,6 +161,12 @@ public:
std::complex<double> getIQBalance(const int direction, const size_t channel) const;
+ bool hasFrequencyCorrection(const int direction, const size_t channel) const;
+
+ void setFrequencyCorrection(const int direction, const size_t channel, const double value);
+
+ double getFrequencyCorrection(const int direction, const size_t channel) const;
+
/*******************************************************************
* Gain API
******************************************************************/
@@ -215,6 +221,8 @@ public:
std::vector<double> listSampleRates(const int direction, const size_t channel) const;
+ SoapySDR::RangeList getSampleRateRange(const int direction, const size_t channel) const;
+
/*******************************************************************
* Bandwidth API
******************************************************************/
@@ -291,6 +299,10 @@ public:
unsigned readRegister(const unsigned addr) const;
+ void writeRegisters(const std::string &name, const unsigned addr, const std::vector<unsigned> &value);
+
+ std::vector<unsigned> readRegisters(const std::string &name, const unsigned addr, const size_t length) const;
+
/*******************************************************************
* Settings API
******************************************************************/
@@ -351,7 +363,8 @@ public:
private:
SoapySocketSession _sess;
- SoapyRPCSocket _sock;
+ mutable SoapyRPCSocket _sock;
SoapyLogAcceptor *_logAcceptor;
- std::mutex _mutex;
+ mutable std::mutex _mutex;
+ std::string _defaultStreamProt;
};
diff --git a/client/Streaming.cpp b/client/Streaming.cpp
index 2b35bd1..21ba4a7 100644
--- a/client/Streaming.cpp
+++ b/client/Streaming.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2016 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include <SoapySDR/Logger.hpp>
@@ -12,10 +12,6 @@
#include "SoapyStreamEndpoint.hpp"
#include <algorithm> //std::min, std::find
-//lazy fix for the const call issue -- FIXME
-#define _mutex const_cast<std::mutex &>(_mutex)
-#define _sock const_cast<SoapyRPCSocket &>(_sock)
-
std::vector<std::string> SoapyRemoteDevice::__getRemoteOnlyStreamFormats(const int direction, const size_t channel) const
{
std::lock_guard<std::mutex> lock(_mutex);
@@ -130,19 +126,23 @@ SoapySDR::Stream *SoapyRemoteDevice::setupStream(
const int direction,
const std::string &localFormat,
const std::vector<size_t> &channels_,
- const SoapySDR::Kwargs &args)
+ const SoapySDR::Kwargs &args_)
{
//default to channel 0 when not specified
//the channels vector cannot be empty
//its used for stream endpoint allocation
auto channels = channels_;
if (channels.empty()) channels.push_back(0);
+ SoapySDR::Kwargs args(args_); //read/write copy
//use the remote device's native stream format and scale factor when the conversion is supported
double nativeScaleFactor = 0.0;
auto nativeFormat = this->getNativeStreamFormat(direction, channels.front(), nativeScaleFactor);
const bool useNative = (localFormat == nativeFormat) or
(localFormat == SOAPY_SDR_CF32 and nativeFormat == SOAPY_SDR_CS16) or
+ (localFormat == SOAPY_SDR_CF32 and nativeFormat == SOAPY_SDR_CS12) or
+ (localFormat == SOAPY_SDR_CS16 and nativeFormat == SOAPY_SDR_CS12) or
+ (localFormat == SOAPY_SDR_CS16 and nativeFormat == SOAPY_SDR_CS8) or
(localFormat == SOAPY_SDR_CF32 and nativeFormat == SOAPY_SDR_CS8) or
(localFormat == SOAPY_SDR_CF32 and nativeFormat == SOAPY_SDR_CU8);
@@ -158,13 +158,27 @@ SoapySDR::Stream *SoapyRemoteDevice::setupStream(
const auto scaleFactorIt = args.find(SOAPY_REMOTE_KWARG_SCALAR);
if (scaleFactorIt != args.end()) scaleFactor = std::stod(scaleFactorIt->second);
- size_t mtu = SOAPY_REMOTE_DEFAULT_ENDPOINT_MTU;
+ //determine reliable stream mode with tcp or datagram mode
+ std::string prot = _defaultStreamProt;
+ const auto protIt = args.find(SOAPY_REMOTE_KWARG_PROT);
+ if (protIt != args.end()) prot = protIt->second;
+ const bool datagramMode = (prot == "udp");
+ if (prot == "udp") {}
+ else if (prot == "tcp") {}
+ else throw std::runtime_error(
+ "SoapyRemote::setupStream() protcol not supported;"
+ "expected 'udp' or 'tcp', but got '"+prot+"'");
+ args[SOAPY_REMOTE_KWARG_PROT] = prot;
+
+ size_t mtu = datagramMode?SOAPY_REMOTE_DEFAULT_ENDPOINT_MTU:SOAPY_REMOTE_SOCKET_BUFFMAX;
const auto mtuIt = args.find(SOAPY_REMOTE_KWARG_MTU);
if (mtuIt != args.end()) mtu = size_t(std::stod(mtuIt->second));
+ args[SOAPY_REMOTE_KWARG_MTU] = std::to_string(mtu);
size_t window = SOAPY_REMOTE_DEFAULT_ENDPOINT_WINDOW;
const auto windowIt = args.find(SOAPY_REMOTE_KWARG_WINDOW);
if (windowIt != args.end()) window = size_t(std::stod(windowIt->second));
+ args[SOAPY_REMOTE_KWARG_WINDOW] = std::to_string(window);
SoapySDR::logf(SOAPY_SDR_INFO, "SoapyRemote::setup%sStream(remoteFormat=%s, localFormat=%s, scaleFactor=%g, mtu=%d, window=%d)",
(direction == SOAPY_SDR_RX)?"Rx":"Tx", remoteFormat.c_str(), localFormat.c_str(), scaleFactor, int(mtu), int(window));
@@ -173,6 +187,9 @@ SoapySDR::Stream *SoapyRemoteDevice::setupStream(
ConvertTypes convertType = CONVERT_MEMCPY;
if (localFormat == remoteFormat) convertType = CONVERT_MEMCPY;
else if (localFormat == SOAPY_SDR_CF32 and remoteFormat == SOAPY_SDR_CS16) convertType = CONVERT_CF32_CS16;
+ else if (localFormat == SOAPY_SDR_CF32 and remoteFormat == SOAPY_SDR_CS12) convertType = CONVERT_CF32_CS12;
+ else if (localFormat == SOAPY_SDR_CS16 and remoteFormat == SOAPY_SDR_CS12) convertType = CONVERT_CS16_CS12;
+ else if (localFormat == SOAPY_SDR_CS16 and remoteFormat == SOAPY_SDR_CS8) convertType = CONVERT_CS16_CS8;
else if (localFormat == SOAPY_SDR_CF32 and remoteFormat == SOAPY_SDR_CS8) convertType = CONVERT_CF32_CS8;
else if (localFormat == SOAPY_SDR_CF32 and remoteFormat == SOAPY_SDR_CU8) convertType = CONVERT_CF32_CU8;
else throw std::runtime_error(
@@ -192,28 +209,33 @@ SoapySDR::Stream *SoapyRemoteDevice::setupStream(
const auto localNode = SoapyURL(_sock.getsockname()).getNode();
const auto remoteNode = SoapyURL(_sock.getpeername()).getNode();
- //bind the stream socket to an automatic port
- const auto bindURL = SoapyURL("udp", localNode, "0").toString();
- int ret = data->streamSock.bind(bindURL);
- if (ret != 0)
+ //bind the receiver side of the sockets in datagram mode
+ std::string clientBindPort, statusBindPort;
+ if (datagramMode)
{
- const std::string errorMsg = data->streamSock.lastErrorMsg();
- delete data;
- throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
- }
- SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream bound to %s", data->streamSock.getsockname().c_str());
- const auto clientBindPort = SoapyURL(data->streamSock.getsockname()).getService();
+ //bind the stream socket to an automatic port
+ const auto bindURL = SoapyURL("udp", localNode, "0").toString();
+ int ret = data->streamSock.bind(bindURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data->streamSock.lastErrorMsg();
+ delete data;
+ throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream bound to %s", data->streamSock.getsockname().c_str());
+ clientBindPort = SoapyURL(data->streamSock.getsockname()).getService();
- //bind the status socket to an automatic port
- ret = data->statusSock.bind(bindURL);
- if (ret != 0)
- {
- const std::string errorMsg = data->statusSock.lastErrorMsg();
- delete data;
- throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
+ //bind the status socket to an automatic port
+ ret = data->statusSock.bind(bindURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data->statusSock.lastErrorMsg();
+ delete data;
+ throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Client side status bound to %s", data->statusSock.getsockname().c_str());
+ statusBindPort = SoapyURL(data->statusSock.getsockname()).getService();
}
- SoapySDR::logf(SOAPY_SDR_INFO, "Client side status bound to %s", data->statusSock.getsockname().c_str());
- const auto statusBindPort = SoapyURL(data->statusSock.getsockname()).getService();
//setup the remote end of the stream
std::lock_guard<std::mutex> lock(_mutex);
@@ -227,25 +249,53 @@ SoapySDR::Stream *SoapyRemoteDevice::setupStream(
packer & statusBindPort;
packer();
- SoapyRPCUnpacker unpacker(_sock);
+ //for tcp mode: get the binding port here and connect to it
std::string serverBindPort;
+ if (not datagramMode)
+ {
+ SoapyRPCUnpacker unpackerTcp(_sock);
+ unpackerTcp & serverBindPort;
+ const auto connectURL = SoapyURL(prot, remoteNode, serverBindPort).toString();
+ int ret = data->streamSock.connect(connectURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data->streamSock.lastErrorMsg();
+ delete data;
+ throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ }
+ ret = data->statusSock.connect(connectURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data->statusSock.lastErrorMsg();
+ delete data;
+ throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ }
+ }
+
+ //and wait for the response with binding port and stream id
+ SoapyRPCUnpacker unpacker(_sock);
unpacker & data->streamId;
unpacker & serverBindPort;
- //connect the stream socket to the specified port
- const auto connectURL = SoapyURL("udp", remoteNode, serverBindPort).toString();
- ret = data->streamSock.connect(connectURL);
- if (ret != 0)
+ //connect the sending end of the stream socket
+ if (datagramMode)
{
- const std::string errorMsg = data->streamSock.lastErrorMsg();
- delete data;
- throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ //connect the stream socket to the specified port
+ const auto connectURL = SoapyURL(prot, remoteNode, serverBindPort).toString();
+ int ret = data->streamSock.connect(connectURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data->streamSock.lastErrorMsg();
+ delete data;
+ throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream connected to %s", data->streamSock.getpeername().c_str());
}
- SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream connected to %s", data->streamSock.getpeername().c_str());
//create endpoint
data->endpoint = new SoapyStreamEndpoint(data->streamSock, data->statusSock,
- direction == SOAPY_SDR_RX, channels.size(), SoapySDR::formatToSize(remoteFormat), mtu, window);
+ datagramMode, direction == SOAPY_SDR_RX, channels.size(),
+ SoapySDR::formatToSize(remoteFormat), mtu, window);
return (SoapySDR::Stream *)data;
}
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 8967291..7bcb359 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -31,6 +31,7 @@ CHECK_INCLUDE_FILES(sys/socket.h HAS_SYS_SOCKET_H)
CHECK_INCLUDE_FILES(arpa/inet.h HAS_ARPA_INET_H)
CHECK_INCLUDE_FILES(ifaddrs.h HAS_IFADDRS_H)
CHECK_INCLUDE_FILES(net/if.h HAS_NET_IF_H)
+CHECK_INCLUDE_FILES(fcntl.h HAS_FCNTL_H)
#network libraries
if (WIN32)
diff --git a/common/SoapyRPCPacker.cpp b/common/SoapyRPCPacker.cpp
index e768aff..bfbaa9b 100644
--- a/common/SoapyRPCPacker.cpp
+++ b/common/SoapyRPCPacker.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "SoapySocketDefs.hpp"
#include "SoapyRemoteDefs.hpp"
#include "SoapyRPCSocket.hpp"
#include "SoapyRPCPacker.hpp"
+#include <SoapySDR/Version.hpp> //feature defines
#include <cfloat> //DBL_MANT_DIG
#include <cmath> //frexp
#include <cstring> //memcpy
@@ -12,11 +13,12 @@
#include <algorithm> //min, max
#include <stdexcept>
-SoapyRPCPacker::SoapyRPCPacker(SoapyRPCSocket &sock):
+SoapyRPCPacker::SoapyRPCPacker(SoapyRPCSocket &sock, unsigned int remoteRPCVersion):
_sock(sock),
_message(NULL),
_size(0),
- _capacity(0)
+ _capacity(0),
+ _remoteRPCVersion(remoteRPCVersion)
{
//default allocation
this->ensureSpace(512);
@@ -129,6 +131,16 @@ void SoapyRPCPacker::operator&(const SoapySDR::Range &value)
*this & SOAPY_REMOTE_RANGE;
*this & value.minimum();
*this & value.maximum();
+
+ //a step size is sent when the remote version matches our current
+ if (_remoteRPCVersion >= SoapyRPCVersion)
+ {
+ #ifdef SOAPY_SDR_API_HAS_RANGE_TYPE_STEP
+ *this & value.step();
+ #else
+ *this & double(0.0);
+ #endif
+ }
}
void SoapyRPCPacker::operator&(const SoapySDR::RangeList &value)
diff --git a/common/SoapyRPCPacker.hpp b/common/SoapyRPCPacker.hpp
index d6b0734..0fe3117 100644
--- a/common/SoapyRPCPacker.hpp
+++ b/common/SoapyRPCPacker.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -18,7 +18,7 @@ class SoapyRPCSocket;
class SOAPY_REMOTE_API SoapyRPCPacker
{
public:
- SoapyRPCPacker(SoapyRPCSocket &sock);
+ SoapyRPCPacker(SoapyRPCSocket &sock, unsigned int remoteRPCVersion = SoapyRPCVersion);
~SoapyRPCPacker(void);
@@ -114,4 +114,5 @@ private:
char *_message;
size_t _size;
size_t _capacity;
+ unsigned int _remoteRPCVersion;
};
diff --git a/common/SoapyRPCSocket.cpp b/common/SoapyRPCSocket.cpp
index 7bdbad8..1e121ee 100644
--- a/common/SoapyRPCSocket.cpp
+++ b/common/SoapyRPCSocket.cpp
@@ -181,6 +181,83 @@ int SoapyRPCSocket::connect(const std::string &url)
return ret;
}
+int SoapyRPCSocket::connect(const std::string &url, const long timeoutUs)
+{
+ SoapyURL urlObj(url);
+ SockAddrData addr;
+ const auto errorMsg = urlObj.toSockAddr(addr);
+ if (not errorMsg.empty())
+ {
+ this->reportError("getaddrinfo("+url+")", errorMsg);
+ return -1;
+ }
+
+ if (this->null()) _sock = ::socket(addr.addr()->sa_family, urlObj.getType(), 0);
+ if (this->null()) return -1;
+ if (urlObj.getType() == SOCK_STREAM) this->setDefaultTcpSockOpts();
+
+ //enable non blocking
+ int ret = this->setNonBlocking(true);
+ if (ret != 0) return ret;
+
+ //non blocking connect, check for non busy
+ ret = ::connect(_sock, addr.addr(), addr.addrlen());
+ if (ret != 0 and SOCKET_ERRNO != SOCKET_EINPROGRESS)
+ {
+ this->reportError("connect("+url+")");
+ return ret;
+ }
+
+ //fill in the select structures
+ struct timeval tv;
+ tv.tv_sec = timeoutUs / 1000000;
+ tv.tv_usec = timeoutUs % 1000000;
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(_sock, &fds);
+
+ //wait for connect or timeout
+ ret = ::select(_sock+1, NULL, &fds, NULL, &tv);
+ if (ret != 1)
+ {
+ this->reportError("connect("+url+")", SOCKET_ETIMEDOUT);
+ return -1;
+ }
+
+ //get the error code from connect()
+ int opt = 0;
+ socklen_t optlen = sizeof(opt);
+ ::getsockopt(_sock, SOL_SOCKET, SO_ERROR, (char *)&opt, &optlen);
+ if (opt != 0)
+ {
+ this->reportError("connect("+url+")", opt);
+ return opt;
+ }
+
+ //revert non blocking on socket
+ ret = this->setNonBlocking(false);
+ if (ret != 0) return ret;
+
+ return opt;
+}
+
+int SoapyRPCSocket::setNonBlocking(const bool nonblock)
+{
+ int ret = 0;
+ #ifdef _MSC_VER
+ u_long mode = nonblock?1:0; // 1 to enable non-blocking socket
+ ret = ioctlsocket(_sock, FIONBIO, &mode);
+ #else
+ int mode = fcntl(_sock, F_GETFL, 0);
+ if (nonblock) mode |= O_NONBLOCK;
+ else mode &= ~(O_NONBLOCK);
+ ret = fcntl(_sock, F_SETFL, mode);
+ #endif
+ if (ret != 0) this->reportError("setNonBlocking("+std::string(nonblock?"true":"false")+")");
+ return ret;
+}
+
/*!
* OSX doesn't support automatic ipv6mr_interface = 0.
* The following code attempts to work around this issue
@@ -393,7 +470,11 @@ static std::string errToString(const int err)
void SoapyRPCSocket::reportError(const std::string &what)
{
- const int err = SOCKET_ERRNO;
+ this->reportError(what, SOCKET_ERRNO);
+}
+
+void SoapyRPCSocket::reportError(const std::string &what, const int err)
+{
if (err == 0) _lastErrorMsg = what;
else this->reportError(what, std::to_string(err) + ": " + errToString(err));
}
diff --git a/common/SoapyRPCSocket.hpp b/common/SoapyRPCSocket.hpp
index 48d4361..52a13c0 100644
--- a/common/SoapyRPCSocket.hpp
+++ b/common/SoapyRPCSocket.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -79,6 +79,14 @@ public:
int connect(const std::string &url);
/*!
+ * Connect to client with a timeout is microseconds.
+ */
+ int connect(const std::string &url, const long timeoutUs);
+
+ //! set or clear non blocking on socket
+ int setNonBlocking(const bool nonblock);
+
+ /*!
* Join a multi-cast group.
* \param group the url for the multicast group and port number
* \param loop specify to receive local loopback
@@ -152,6 +160,7 @@ private:
std::string _lastErrorMsg;
void reportError(const std::string &what, const std::string &errorMsg);
+ void reportError(const std::string &what, const int err);
void reportError(const std::string &what);
void setDefaultTcpSockOpts(void);
};
diff --git a/common/SoapyRPCUnpacker.cpp b/common/SoapyRPCUnpacker.cpp
index 7f7c2e1..6c818af 100644
--- a/common/SoapyRPCUnpacker.cpp
+++ b/common/SoapyRPCUnpacker.cpp
@@ -1,11 +1,13 @@
-// Copyright (c) 2015-2016 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "SoapySocketDefs.hpp"
#include "SoapyRemoteDefs.hpp"
#include "SoapyRPCSocket.hpp"
#include "SoapyRPCUnpacker.hpp"
+#include "SoapyRPCPacker.hpp"
#include <SoapySDR/Logger.hpp>
+#include <SoapySDR/Version.hpp> //feature defines
#include <cfloat> //DBL_MANT_DIG
#include <cmath> //ldexp
#include <cstring> //memcpy
@@ -13,12 +15,41 @@
#include <algorithm> //min, max
#include <stdexcept>
-SoapyRPCUnpacker::SoapyRPCUnpacker(SoapyRPCSocket &sock, const bool autoRecv):
+static void testServerConnection(const std::string &url)
+{
+ SoapyRPCSocket s;
+ int ret = s.connect(url, SOAPY_REMOTE_SOCKET_TIMEOUT_US);
+ if (ret != 0) throw std::runtime_error("SoapyRPCUnpacker::recv() FAIL test server connection: "+std::string(s.lastErrorMsg()));
+ SoapyRPCPacker packerHangup(s);
+ packerHangup & SOAPY_REMOTE_HANGUP;
+ packerHangup();
+ s.selectRecv(SOAPY_REMOTE_SOCKET_TIMEOUT_US);
+}
+
+SoapyRPCUnpacker::SoapyRPCUnpacker(SoapyRPCSocket &sock, const bool autoRecv, const long timeoutUs):
_sock(sock),
_message(NULL),
_offset(0),
- _capacity(0)
+ _capacity(0),
+ _remoteRPCVersion(SoapyRPCVersion)
{
+ //auto recv expects a reply packet within a reasonable time window
+ //or else the link might be down, in which case we throw an error.
+ //Calls are allowed to take a long time (up to 31 seconds).
+ //However, we continually check that the server is active
+ //so that we can tear down immediately if the server goes away.
+ if (timeoutUs >= 0)
+ {
+ auto subTimeout = std::min<long>(timeoutUs, 1000000); //1 second
+ while (true)
+ {
+ if (_sock.selectRecv(subTimeout)) break;
+ testServerConnection(_sock.getpeername());
+ subTimeout *= 2; //server is up, increase timeout check
+ if (subTimeout >= timeoutUs) throw std::runtime_error("SoapyRPCUnpacker::recv() TIMEOUT: "+std::string(_sock.lastErrorMsg()));
+ }
+ }
+
if (autoRecv) this->recv();
}
@@ -48,6 +79,7 @@ void SoapyRPCUnpacker::recv(void)
{
throw std::runtime_error("SoapyRPCUnpacker::recv() FAIL: header word");
}
+ _remoteRPCVersion = ntohl(header.version);
//TODO ignoring the version for now
//the check may need to be delicate with the version major, minor vs patch number
const size_t length = ntohl(header.length);
@@ -187,10 +219,21 @@ void SoapyRPCUnpacker::operator&(std::string &value)
void SoapyRPCUnpacker::operator&(SoapySDR::Range &value)
{
UNPACK_TYPE_HELPER(SOAPY_REMOTE_RANGE);
- double minimum = 0.0, maximum = 0.0;
+ double minimum = 0.0, maximum = 0.0, step = 0.0;
*this & minimum;
*this & maximum;
+
+ //a step size is sent when the remote version matches our current
+ if (_remoteRPCVersion >= SoapyRPCVersion)
+ {
+ *this & step;
+ }
+
+ #ifdef SOAPY_SDR_API_HAS_RANGE_TYPE_STEP
+ value = SoapySDR::Range(minimum, maximum, step);
+ #else
value = SoapySDR::Range(minimum, maximum);
+ #endif
}
void SoapyRPCUnpacker::operator&(SoapySDR::RangeList &value)
diff --git a/common/SoapyRPCUnpacker.hpp b/common/SoapyRPCUnpacker.hpp
index 6fee795..3104135 100644
--- a/common/SoapyRPCUnpacker.hpp
+++ b/common/SoapyRPCUnpacker.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -17,7 +17,7 @@ class SoapyRPCSocket;
class SOAPY_REMOTE_API SoapyRPCUnpacker
{
public:
- SoapyRPCUnpacker(SoapyRPCSocket &sock, const bool autoRecv = true);
+ SoapyRPCUnpacker(SoapyRPCSocket &sock, const bool autoRecv = true, const long timeoutUs = 30000000);
~SoapyRPCUnpacker(void);
@@ -104,6 +104,12 @@ public:
//! Unpack a list of arg infos
void operator&(SoapySDR::ArgInfoList &value);
+ //! Get the received RPC version number
+ unsigned int remoteRPCVersion(void) const
+ {
+ return _remoteRPCVersion;
+ }
+
private:
void ensureSpace(const size_t length);
@@ -112,4 +118,5 @@ private:
char *_message;
size_t _offset;
size_t _capacity;
+ unsigned int _remoteRPCVersion;
};
diff --git a/common/SoapyRemoteDefs.hpp b/common/SoapyRemoteDefs.hpp
index 23ebe16..368ae71 100644
--- a/common/SoapyRemoteDefs.hpp
+++ b/common/SoapyRemoteDefs.hpp
@@ -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
@@ -23,6 +23,9 @@
//! Stream args key to set the buffer MTU bytes for network transfers
#define SOAPY_REMOTE_KWARG_MTU (SOAPY_REMOTE_KWARG_PREFIX "mtu")
+//! Stream args key to select the stream's protocol (tcp or udp)
+#define SOAPY_REMOTE_KWARG_PROT (SOAPY_REMOTE_KWARG_PREFIX "prot")
+
/*!
* Default stream transfer size (under network MTU).
* Larger transfer sizes may not be supported in hardware
@@ -64,7 +67,7 @@
#define SOAPY_REMOTE_DEFAULT_SERVICE "55132"
//! Use this timeout for every socket poll loop
-#define SOAPY_REMOTE_SOCKET_TIMEOUT_US (50*1000) //50 ms
+#define SOAPY_REMOTE_SOCKET_TIMEOUT_US (500*1000) //500 ms
//! Backlog count for the server socket listen
#define SOAPY_REMOTE_LISTEN_BACKLOG 100
@@ -92,7 +95,7 @@
**********************************************************************/
//major, minor, patch when this was last updated
//bump the version number when changes are made
-static const unsigned int SoapyRPCVersion = 0x000300;
+static const unsigned int SoapyRPCVersion = 0x000400;
enum SoapyRemoteTypes
{
@@ -167,6 +170,9 @@ enum SoapyRemoteCalls
SOAPY_REMOTE_HAS_IQ_BALANCE_MODE = 606,
SOAPY_REMOTE_SET_IQ_BALANCE_MODE = 607,
SOAPY_REMOTE_GET_IQ_BALANCE_MODE = 608,
+ SOAPY_REMOTE_HAS_FREQUENCY_CORRECTION = 503,
+ SOAPY_REMOTE_SET_FREQUENCY_CORRECTION = 504,
+ SOAPY_REMOTE_GET_FREQUENCY_CORRECTION = 505,
//gain
SOAPY_REMOTE_LIST_GAINS = 700,
@@ -194,6 +200,7 @@ enum SoapyRemoteCalls
SOAPY_REMOTE_SET_SAMPLE_RATE = 900,
SOAPY_REMOTE_GET_SAMPLE_RATE = 901,
SOAPY_REMOTE_LIST_SAMPLE_RATES = 902,
+ SOAPY_REMOTE_GET_SAMPLE_RATE_RANGE = 907,
//bandwidth
SOAPY_REMOTE_SET_BANDWIDTH = 903,
@@ -232,6 +239,8 @@ enum SoapyRemoteCalls
SOAPY_REMOTE_LIST_REGISTER_INTERFACES = 1302,
SOAPY_REMOTE_WRITE_REGISTER_NAMED = 1303,
SOAPY_REMOTE_READ_REGISTER_NAMED = 1304,
+ SOAPY_REMOTE_WRITE_REGISTERS = 1305,
+ SOAPY_REMOTE_READ_REGISTERS = 1306,
//settings
SOAPY_REMOTE_WRITE_SETTING = 1400,
diff --git a/common/SoapySocketDefs.in.hpp b/common/SoapySocketDefs.in.hpp
index 9356ed8..19ae419 100644
--- a/common/SoapySocketDefs.in.hpp
+++ b/common/SoapySocketDefs.in.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// SPDX-License-Identifier: BSL-1.0
// ** This header should be included first, to avoid compile errors.
@@ -73,6 +73,11 @@ typedef int socklen_t;
#include <net/if.h> //if_nametoindex
#endif //HAS_NET_IF_H
+#cmakedefine HAS_FCNTL_H
+#ifdef HAS_FCNTL_H
+#include <fcntl.h> //fcntl and constants
+#endif //HAS_FCNTL_H
+
/***********************************************************************
* htonll and ntohll for GCC
**********************************************************************/
@@ -104,8 +109,12 @@ typedef int socklen_t;
**********************************************************************/
#ifdef _MSC_VER
#define SOCKET_ERRNO WSAGetLastError()
+#define SOCKET_EINPROGRESS WSAEWOULDBLOCK
+#define SOCKET_ETIMEDOUT WSAETIMEDOUT
#else
#define SOCKET_ERRNO errno
+#define SOCKET_EINPROGRESS EINPROGRESS
+#define SOCKET_ETIMEDOUT ETIMEDOUT
#endif
/***********************************************************************
diff --git a/common/SoapyStreamEndpoint.cpp b/common/SoapyStreamEndpoint.cpp
index 4705031..5722412 100644
--- a/common/SoapyStreamEndpoint.cpp
+++ b/common/SoapyStreamEndpoint.cpp
@@ -8,6 +8,7 @@
#include "SoapyURLUtils.hpp"
#include "SoapyRemoteDefs.hpp"
#include "SoapySocketDefs.hpp"
+#include <algorithm> //min/max
#include <cassert>
#include <cstdint>
@@ -28,6 +29,7 @@ struct StreamDatagramHeader
SoapyStreamEndpoint::SoapyStreamEndpoint(
SoapyRPCSocket &streamSock,
SoapyRPCSocket &statusSock,
+ const bool datagramMode,
const bool isRecv,
const size_t numChans,
const size_t elemSize,
@@ -35,6 +37,7 @@ SoapyStreamEndpoint::SoapyStreamEndpoint(
const size_t window):
_streamSock(streamSock),
_statusSock(statusSock),
+ _datagramMode(datagramMode),
_xferSize(mtu-PROTO_HEADER_SIZE),
_numChans(numChans),
_elemSize(elemSize),
@@ -168,6 +171,8 @@ bool SoapyStreamEndpoint::waitRecv(const long timeoutUs)
int SoapyStreamEndpoint::acquireRecv(size_t &handle, const void **buffs, int &flags, long long &timeNs)
{
+ int ret = 0;
+
//no available handles, the user is hoarding them...
if (_numHandlesAcquired == _buffData.size())
{
@@ -181,23 +186,38 @@ int SoapyStreamEndpoint::acquireRecv(size_t &handle, const void **buffs, int &fl
//receive into the buffer
assert(not _streamSock.null());
- int ret = _streamSock.recv(data.buff.data(), data.buff.size());
+ if (_datagramMode) ret = _streamSock.recv(data.buff.data(), data.buff.size());
+ else ret = _streamSock.recv(data.buff.data(), HEADER_SIZE, MSG_WAITALL);
if (ret < 0)
{
SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::acquireRecv(), FAILED %s", _streamSock.lastErrorMsg());
return SOAPY_SDR_STREAM_ERROR;
}
+ size_t bytesRecvd = size_t(ret);
_receiveInitial = true;
//check the header
auto header = (const StreamDatagramHeader*)data.buff.data();
size_t bytes = ntohl(header->bytes);
- if (bytes > size_t(ret))
+
+ if (_datagramMode and bytes > bytesRecvd)
{
SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::acquireRecv(%d bytes), FAILED %d\n"
"This MTU setting may be unachievable. Check network configuration.", int(bytes), ret);
return SOAPY_SDR_STREAM_ERROR;
}
+
+ else while (bytesRecvd < bytes)
+ {
+ ret = _streamSock.recv(data.buff.data()+bytesRecvd, std::min<size_t>(SOAPY_REMOTE_SOCKET_BUFFMAX, bytes-bytesRecvd));
+ if (ret < 0)
+ {
+ SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::acquireRecv(), FAILED %s", _streamSock.lastErrorMsg());
+ return SOAPY_SDR_STREAM_ERROR;
+ }
+ bytesRecvd += size_t(ret);
+ }
+
const int numElemsOrErr = int(ntohl(header->elems));
//dropped or out of order packets
@@ -307,14 +327,21 @@ void SoapyStreamEndpoint::releaseSend(const size_t handle, const int numElemsOrE
//send from the buffer
assert(not _streamSock.null());
- int ret = _streamSock.send(data.buff.data(), bytes);
- if (ret < 0)
- {
- SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::releaseSend(), FAILED %s", _streamSock.lastErrorMsg());
- }
- else if (size_t(ret) != bytes)
+ size_t bytesSent = 0;
+ while (bytesSent < bytes)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::releaseSend(%d bytes), FAILED %d", int(bytes), ret);
+ int ret = _streamSock.send(data.buff.data()+bytesSent, std::min<size_t>(SOAPY_REMOTE_SOCKET_BUFFMAX, bytes-bytesSent));
+ if (ret < 0)
+ {
+ SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::releaseSend(), FAILED %s", _streamSock.lastErrorMsg());
+ break;
+ }
+ bytesSent += size_t(ret);
+ if (not _datagramMode) continue;
+ if (bytesSent != bytes)
+ {
+ SoapySDR::logf(SOAPY_SDR_ERROR, "StreamEndpoint::releaseSend(%d bytes), FAILED %d", int(bytes), ret);
+ }
}
//actually release in order of handle index
diff --git a/common/SoapyStreamEndpoint.hpp b/common/SoapyStreamEndpoint.hpp
index 93587ea..ceac48a 100644
--- a/common/SoapyStreamEndpoint.hpp
+++ b/common/SoapyStreamEndpoint.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2016 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -19,6 +19,7 @@ public:
SoapyStreamEndpoint(
SoapyRPCSocket &streamSock,
SoapyRPCSocket &statusSock,
+ const bool datagramMode,
const bool isRecv,
const size_t numChans,
const size_t elemSize,
@@ -125,6 +126,7 @@ public:
private:
SoapyRPCSocket &_streamSock;
SoapyRPCSocket &_statusSock;
+ const bool _datagramMode;
const size_t _xferSize;
const size_t _numChans;
const size_t _elemSize;
diff --git a/debian/changelog b/debian/changelog
index 0f49d24..52f7e31 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,22 @@
-soapyremote (0.3.2) unstable; urgency=low
+soapyremote (0.4.2-1) unstable; urgency=low
+
+ * Release 0.4.2 (2017-07-31)
+
+ -- Josh Blum <josh at pothosware.com> Mon, 31 Jul 2017 09:15:34 -0000
+
+soapyremote (0.4.1-1) unstable; urgency=low
+
+ * Release 0.4.1 (2017-06-08)
+
+ -- Josh Blum <josh at pothosware.com> Thu, 08 Jun 2017 18:18:32 -0000
+
+soapyremote (0.4.0-1) unstable; urgency=low
+
+ * Release 0.4.0 (2017-04-29)
+
+ -- Josh Blum <josh at pothosware.com> Sat, 29 Apr 2017 10:11:25 -0000
+
+soapyremote (0.3.2-1) unstable; urgency=low
* Release 0.3.2 (2016-12-04)
diff --git a/debian/control b/debian/control
index 16c85cc..3b67b88 100644
--- a/debian/control
+++ b/debian/control
@@ -11,7 +11,7 @@ Homepage: https://github.com/pothosware/SoapyRemote/wiki
Vcs-Git: https://github.com/pothosware/SoapyRemote.git
Vcs-Browser: https://github.com/pothosware/SoapyRemote
-Package: soapysdr0.5-2-module-remote
+Package: soapysdr0.6-module-remote
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
@@ -20,7 +20,7 @@ Description: Soapy Remote - Remote device support for Soapy SDR.
Package: soapysdr-module-remote
Architecture: all
-Depends: soapysdr0.5-2-module-remote, ${misc:Depends}
+Depends: soapysdr0.6-module-remote, ${misc:Depends}
Description: Soapy Remote - Remote device support for Soapy SDR.
A Soapy module that supports remote devices within the Soapy API.
.
@@ -30,6 +30,6 @@ Description: Soapy Remote - Remote device support for Soapy SDR.
Package: soapysdr-server
Section: libs
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
+Depends: ${shlibs:Depends}, ${misc:Depends}, init-system-helpers
Description: Soapy Remote - Remote device support for Soapy SDR.
The SoapySDRServer server application for remote devices.
diff --git a/debian/copyright b/debian/copyright
index 372433f..7154043 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@ Source: https://github.com/pothosware/SoapyRemote/wiki
Files: *
Copyright:
- Copyright (c) 2015-2016 Josh Blum <josh at pothosware.com>
+ Copyright (c) 2015-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/soapysdr-server.install b/debian/soapysdr-server.install
index ef04224..b968fd3 100644
--- a/debian/soapysdr-server.install
+++ b/debian/soapysdr-server.install
@@ -1,3 +1,4 @@
usr/bin/
-usr/lib/systemd/
+#systemd-service-file-outside-lib
+usr/lib/systemd/ lib/
usr/lib/sysctl.d/
diff --git a/debian/soapysdr-server.postrm b/debian/soapysdr-server.postrm
new file mode 100644
index 0000000..185dbe4
--- /dev/null
+++ b/debian/soapysdr-server.postrm
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "remove" ]; then
+ deb-systemd-helper mask SoapySDRServer.service > /dev/null
+fi
+
+if [ "$1" = "remove" ]; then
+ deb-systemd-helper purge SoapySDRServer.service > /dev/null
+ deb-systemd-helper unmask SoapySDRServer.service > /dev/null
+fi
+
+#DEBHELPER#
diff --git a/debian/soapysdr-server.prerm b/debian/soapysdr-server.prerm
index 8028023..9b75ccc 100644
--- a/debian/soapysdr-server.prerm
+++ b/debian/soapysdr-server.prerm
@@ -2,8 +2,7 @@
set -e
if [ "$1" = "remove" ]; then
- systemctl stop SoapySDRServer
- systemctl disable SoapySDRServer
+ deb-systemd-invoke stop SoapySDRServer.service > /dev/null
fi
#DEBHELPER#
diff --git a/debian/soapysdr0.5-2-module-remote.install b/debian/soapysdr0.6-module-remote.install
similarity index 100%
rename from debian/soapysdr0.5-2-module-remote.install
rename to debian/soapysdr0.6-module-remote.install
diff --git a/server/ClientHandler.cpp b/server/ClientHandler.cpp
index f5e0a11..133b1a8 100644
--- a/server/ClientHandler.cpp
+++ b/server/ClientHandler.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
@@ -63,8 +63,8 @@ bool SoapyClientHandler::handleOnce(void)
if (not _sock.selectRecv(SOAPY_REMOTE_SOCKET_TIMEOUT_US)) return true;
//receive the client's request
- SoapyRPCUnpacker unpacker(_sock);
- SoapyRPCPacker packer(_sock);
+ SoapyRPCUnpacker unpacker(_sock, true, -1/*no timeout*/);
+ SoapyRPCPacker packer(_sock, unpacker.remoteRPCVersion());
//handle the client's request
bool again = true;
@@ -311,6 +311,11 @@ bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &
const auto priorityIt = args.find(SOAPY_REMOTE_KWARG_PRIORITY);
if (priorityIt != args.end()) priority = std::stod(priorityIt->second);
+ std::string prot = "udp";
+ const auto protIt = args.find(SOAPY_REMOTE_KWARG_PROT);
+ if (protIt != args.end()) prot = protIt->second;
+ const bool datagramMode = (prot == "udp");
+
//create stream
auto stream = _dev->setupStream(direction, format, channels, args);
@@ -327,43 +332,82 @@ bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &
const auto localNode = SoapyURL(_sock.getsockname()).getNode();
const auto remoteNode = SoapyURL(_sock.getpeername()).getNode();
- //bind the stream socket to an automatic port
- const auto bindURL = SoapyURL("udp", localNode, "0").toString();
- int ret = data.streamSock.bind(bindURL);
- if (ret != 0)
- {
- const std::string errorMsg = data.streamSock.lastErrorMsg();
- _streamData.erase(data.streamId);
- throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
- }
- SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream bound to %s", data.streamSock.getsockname().c_str());
- const auto serverBindPort = SoapyURL(data.streamSock.getsockname()).getService();
+ const auto bindURL = SoapyURL(prot, localNode, "0").toString();
+ std::string serverBindPort;
- //connect the stream socket to the specified port
- auto connectURL = SoapyURL("udp", remoteNode, clientBindPort).toString();
- ret = data.streamSock.connect(connectURL);
- if (ret != 0)
+ //in udp mode connect to the bound sockets on the client side
+ if (datagramMode)
{
- const std::string errorMsg = data.streamSock.lastErrorMsg();
- _streamData.erase(data.streamId);
- throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ data.streamSock = new SoapyRPCSocket();
+ data.statusSock = new SoapyRPCSocket();
+
+ //bind the stream socket to an automatic port
+ int ret = data.streamSock->bind(bindURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data.streamSock->lastErrorMsg();
+ _streamData.erase(data.streamId);
+ throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream bound to %s", data.streamSock->getsockname().c_str());
+ serverBindPort = SoapyURL(data.streamSock->getsockname()).getService();
+
+ //connect the stream socket to the specified port
+ auto connectURL = SoapyURL("udp", remoteNode, clientBindPort).toString();
+ ret = data.streamSock->connect(connectURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data.streamSock->lastErrorMsg();
+ _streamData.erase(data.streamId);
+ throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream connected to %s", data.streamSock->getpeername().c_str());
+
+ //connect the status socket to the specified port
+ connectURL = SoapyURL("udp", remoteNode, statusBindPort).toString();
+ ret = data.statusSock->connect(connectURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = data.statusSock->lastErrorMsg();
+ _streamData.erase(data.streamId);
+ throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Server side status connected to %s", data.statusSock->getpeername().c_str());
}
- SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream connected to %s", data.streamSock.getpeername().c_str());
- //connect the status socket to the specified port
- connectURL = SoapyURL("udp", remoteNode, statusBindPort).toString();
- ret = data.statusSock.connect(connectURL);
- if (ret != 0)
+ //in tcp mode, setup the server socket to listen,
+ //send the binding port back to the client and
+ //accept the client's new connections
+ else
{
- const std::string errorMsg = data.statusSock.lastErrorMsg();
- _streamData.erase(data.streamId);
- throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
+ SoapyRPCSocket serverSocket;
+ int ret = serverSocket.bind(bindURL);
+ if (ret != 0)
+ {
+ const std::string errorMsg = serverSocket.lastErrorMsg();
+ _streamData.erase(data.streamId);
+ throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
+ }
+ SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream bound to %s", serverSocket.getsockname().c_str());
+ serverBindPort = SoapyURL(serverSocket.getsockname()).getService();
+
+ serverSocket.listen(2);
+ SoapyRPCPacker packerTcp(_sock);
+ packerTcp & serverBindPort;
+ packerTcp();
+ data.streamSock = serverSocket.accept();
+ data.statusSock = serverSocket.accept();
+ if (data.streamSock == nullptr or data.statusSock == nullptr)
+ {
+ const std::string errorMsg = serverSocket.lastErrorMsg();
+ throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- accept FAIL: " + errorMsg);
+ }
}
- SoapySDR::logf(SOAPY_SDR_INFO, "Server side status connected to %s", data.statusSock.getpeername().c_str());
//create endpoint
- data.endpoint = new SoapyStreamEndpoint(data.streamSock, data.statusSock,
- direction == SOAPY_SDR_TX, channels.size(), SoapySDR::formatToSize(format), mtu, window);
+ data.endpoint = new SoapyStreamEndpoint(*data.streamSock, *data.statusSock,
+ datagramMode, direction == SOAPY_SDR_TX, channels.size(),
+ SoapySDR::formatToSize(format), mtu, window);
//start worker thread, this is not backwards,
//receive from device means using a send endpoint
@@ -569,6 +613,54 @@ bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &
} break;
////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_HAS_FREQUENCY_CORRECTION:
+ ////////////////////////////////////////////////////////////////////
+ {
+ char direction = 0;
+ int channel = 0;
+ unpacker & direction;
+ unpacker & channel;
+ #ifdef SOAPY_SDR_API_HAS_FREQUENCY_CORRECTION_API
+ packer & _dev->hasFrequencyCorrection(direction, channel);
+ #else
+ bool result(false);
+ packer & result;
+ #endif
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_SET_FREQUENCY_CORRECTION:
+ ////////////////////////////////////////////////////////////////////
+ {
+ char direction = 0;
+ int channel = 0;
+ double value(0.0);
+ unpacker & direction;
+ unpacker & channel;
+ unpacker & value;
+ #ifdef SOAPY_SDR_API_HAS_FREQUENCY_CORRECTION_API
+ _dev->setFrequencyCorrection(direction, channel, value);
+ #endif
+ packer & SOAPY_REMOTE_VOID;
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_GET_FREQUENCY_CORRECTION:
+ ////////////////////////////////////////////////////////////////////
+ {
+ char direction = 0;
+ int channel = 0;
+ unpacker & direction;
+ unpacker & channel;
+ #ifdef SOAPY_SDR_API_HAS_FREQUENCY_CORRECTION_API
+ packer & _dev->getFrequencyCorrection(direction, channel);
+ #else
+ double result(0.0);
+ packer & result;
+ #endif
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
case SOAPY_REMOTE_LIST_GAINS:
////////////////////////////////////////////////////////////////////
{
@@ -835,6 +927,22 @@ bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &
} break;
////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_GET_SAMPLE_RATE_RANGE:
+ ////////////////////////////////////////////////////////////////////
+ {
+ char direction = 0;
+ int channel = 0;
+ unpacker & direction;
+ unpacker & channel;
+ #ifdef SOAPY_SDR_API_HAS_GET_SAMPLE_RATE_RANGE
+ packer & _dev->getSampleRateRange(direction, channel);
+ #else
+ SoapySDR::RangeList result;
+ packer & result;
+ #endif
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
case SOAPY_REMOTE_SET_BANDWIDTH:
////////////////////////////////////////////////////////////////////
{
@@ -1128,6 +1236,43 @@ bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &
} break;
////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_WRITE_REGISTERS:
+ ////////////////////////////////////////////////////////////////////
+ {
+ std::string name;
+ int addr = 0;
+ std::vector<size_t> value;
+ unpacker & name;
+ unpacker & addr;
+ unpacker & value;
+ #ifdef SOAPY_SDR_API_HAS_NAMED_REGISTERS_API
+ std::vector <unsigned> val (value.begin(), value.end());
+ _dev->writeRegisters(name, unsigned(addr), val);
+ #endif
+ packer & SOAPY_REMOTE_VOID;
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
+ case SOAPY_REMOTE_READ_REGISTERS:
+ ////////////////////////////////////////////////////////////////////
+ {
+ std::string name;
+ int addr = 0;
+ int length;
+ unpacker & name;
+ unpacker & addr;
+ unpacker & length;
+ #ifdef SOAPY_SDR_API_HAS_NAMED_REGISTERS_API
+ std::vector <unsigned> val = _dev->readRegisters(name, unsigned(addr), size_t(length));
+ std::vector <size_t> value (val.begin(), val.end());
+ packer & (value);
+ #else
+ std::vector <size_t> value;
+ packer & (value);
+ #endif
+ } break;
+
+ ////////////////////////////////////////////////////////////////////
case SOAPY_REMOTE_GET_SETTING_INFO:
////////////////////////////////////////////////////////////////////
{
diff --git a/server/ServerStreamData.cpp b/server/ServerStreamData.cpp
index a44e600..063d15d 100644
--- a/server/ServerStreamData.cpp
+++ b/server/ServerStreamData.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2017 Josh Blum
// Copyright (c) 2016-2016 Bastille Networks
// SPDX-License-Identifier: BSL-1.0
@@ -27,6 +27,8 @@ ServerStreamData::ServerStreamData(void):
chanMask(0),
priority(0.0),
streamId(-1),
+ streamSock(nullptr),
+ statusSock(nullptr),
endpoint(nullptr),
streamThread(nullptr),
statusThread(nullptr),
@@ -35,6 +37,12 @@ ServerStreamData::ServerStreamData(void):
return;
}
+ServerStreamData::~ServerStreamData(void)
+{
+ delete streamSock;
+ delete statusSock;
+}
+
void ServerStreamData::startSendThread(void)
{
assert(streamId != -1);
@@ -100,7 +108,7 @@ void ServerStreamData::recvEndpointWork(void)
ret = endpoint->acquireRecv(handle, buffs.data(), flags, timeNs);
if (ret < 0)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "Server-side receive endpoint: %s; worker quitting...", streamSock.lastErrorMsg());
+ SoapySDR::logf(SOAPY_SDR_ERROR, "Server-side receive endpoint: %s; worker quitting...", streamSock->lastErrorMsg());
return;
}
@@ -153,7 +161,7 @@ void ServerStreamData::sendEndpointWork(void)
ret = endpoint->acquireSend(handle, buffs.data());
if (ret < 0)
{
- SoapySDR::logf(SOAPY_SDR_ERROR, "Server-side send endpoint: %s; worker quitting...", streamSock.lastErrorMsg());
+ SoapySDR::logf(SOAPY_SDR_ERROR, "Server-side send endpoint: %s; worker quitting...", streamSock->lastErrorMsg());
return;
}
@@ -182,7 +190,8 @@ void ServerStreamData::sendEndpointWork(void)
//This is a latency optimization to forward to the host ASAP,
//but to use the full bandwidth when more data is available.
//Do not allow this optimization when end of burst or single packet mode to preserve boundaries
- if (elemsRead != 0 and elemsLeft != 0 and (flags & (SOAPY_SDR_END_BURST | SOAPY_SDR_ONE_PACKET)) == 0)
+ static const int trailingFlags(SOAPY_SDR_END_BURST | SOAPY_SDR_ONE_PACKET | SOAPY_SDR_END_ABRUPT);
+ if (elemsRead != 0 and elemsLeft != 0 and (flags & trailingFlags) == 0)
{
int flags1 = 0;
long long timeNs1 = 0;
@@ -193,6 +202,9 @@ void ServerStreamData::sendEndpointWork(void)
elemsLeft -= ret;
elemsRead += ret;
}
+
+ //include trailing flags that come from the second read
+ flags |= (flags1 & trailingFlags);
}
//release the buffer with flags and time from the first read
diff --git a/server/ServerStreamData.hpp b/server/ServerStreamData.hpp
index c9f7ef2..ffd3b66 100644
--- a/server/ServerStreamData.hpp
+++ b/server/ServerStreamData.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2015 Josh Blum
+// Copyright (c) 2015-2016 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#pragma once
@@ -25,6 +25,7 @@ class ServerStreamData
{
public:
ServerStreamData(void);
+ ~ServerStreamData(void);
SoapySDR::Device *device;
SoapySDR::Stream *stream;
@@ -36,10 +37,10 @@ public:
int streamId;
//datagram socket for stream endpoint
- SoapyRPCSocket streamSock;
+ SoapyRPCSocket *streamSock;
//datagram socket for status endpoint
- SoapyRPCSocket statusSock;
+ SoapyRPCSocket *statusSock;
//remote side of the stream endpoint
SoapyStreamEndpoint *endpoint;
diff --git a/system/SoapySDRServer.service.in b/system/SoapySDRServer.service.in
index a1dcb02..058b244 100644
--- a/system/SoapySDRServer.service.in
+++ b/system/SoapySDRServer.service.in
@@ -1,5 +1,7 @@
[Unit]
Description=SoapyRemote network server
+Wants=network-online.target
+After=network-online.target
[Service]
ExecStart=@CMAKE_INSTALL_PREFIX@/bin/SoapySDRServer --bind
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/soapyremote.git
More information about the pkg-hamradio-commits
mailing list