Skip to content
Josh Blum edited this page Oct 28, 2015 · 47 revisions

Remote support for Soapy SDR

https://raw.githubusercontent.com/wiki/pothosware/SoapyRemote/images/soapy_sdr_remote_logo.png

Use any SoapySDR supported device transparently over a local network link. The remote support feature can turn any SDR into a network peripheral.

Potential use-cases for Soapy Remote:

  • share the SDR device over a network
  • use the device in multiple processes
  • or use the device on multiple hosts
  • a multi-threaded abstraction layer
  • aid in embedded-device development
  • or a work-around for software issues
  • adapt an IPv4 SDR for an IPv6 network

Pre-built installers for various systems are available through the Pothos SDR environment.

The remote device support has no additional dependencies other than SoapySDR itself:

The CMake build system will locate SoapySDR development files on your system. The plugin module and SoapySDRServer application will be built and installed into the SoapySDR modules directory and bin/ directory (respectively). The SoapyRemote project must be installed on both the remote and local system.

git clone https://github.com/pothosware/SoapyRemote.git
cd SoapyRemote
mkdir build
cd build
cmake ..
make
sudo make install

Run the server on the remote machine (the machine with the SDR hardware):

SoapySDRServer --bind

Or specify a custom bind address and port:

SoapySDRServer --bind="0.0.0.0:1234"

IPv6 address URLs are also supported:

SoapySDRServer --bind="[::]:1234"

The device should be supported transparently over the network using the standard SoapySDR API, SoapySDRUtil, and any applications built on top of the SoapySDR API. However, users will need to specify an additional device argument to engage the remote support module:

Specify the "remote" key to engage the support module at a specific address. When not specified, the remote module will attempt to automatically discover and enumerate servers on the local network. The value of the "remote" key should be the remote server's hostname or IP address. If a custom port was selected, the value should be specified as "myServer:portNum":

SoapySDRUtil --find="remote=myServer"

Filter out local devices with the "driver" key set to "remote". When the "driver" key specifies the "remote" plugin module, all other plugin modules will be ignored by the device enumeration routine:

SoapySDRUtil --find="remote=myServer, driver=remote"

Specify the "remote:driver" key to filter plugins on the remote system. The args will be rewritten to strip out the "remote:" key prefix. Use the "remote:" prefix to apply keys to the remote device only that would otherwise conflict with local keys:

SoapySDRUtil --find="remote=myServer, remote:driver=bladerf"

Use UHD with a remote device when SoapyUHD is installed. The same instructions for "driver" and "remote" keys apply. We can even use SoapyRemote to share the device locally to several processes:

uhd_find_devices --args="driver=remote,remote=myServer"

#use only SoapyRemote when UHD devices are available locally
uhd_find_devices --args="driver=remote,remote=myServer,type=soapy"

#example use of explicit type filter on remote server
uhd_find_devices --args="driver=remote,remote=myServer,remote:type=b200"

Using the Soapy SDR support included in the GrOsmoSDR project, most devices can be used remotely through the GrOsmoSDR blocks and API.

First make sure that "Soapy" is one of the configured components when building GrOsmoSDR. Next, with the SoapySDRServer running, the following args may be used with the gr-osmosdr source or sink block to work with a remote device.

Key Value Required? Description
remote <myServer> required Specifies the server's hostname or address to SoapyRemote.
soapy 0 optional Instructs GrOsmoSDR to use the Soapy support. Required if GrOsmoSDR might find other devices on the local machine.
driver remote optional Instructs SoapySDR to use the remote module. Required if SoapySDR might find other devices on the local machine.
remote:driver <driverKey> optional Required if SoapySDR might find other devices on the remote machine. Example: "remote:driver=rtlsdr"

Putting it all together:

#No devices locally, only one desired device on the remote server
remoteArgs="remote=myServer"

#One or more local devices, and multiple devices on the remote server
remoteArgs="remote=myServer,soapy=0,driver=remote,remote:driver=rtlsdr"

There are several optional stream arguments for setupStream() that can be used to tweak the performance of the remote stream forwarding. Regardless, we recommend that linux users follow the instructions for sysctrl and limits.conf, as SoapyRemote can automatically take advantage of these reconfigured settings.

The remote format key specifies the stream format that should be used on the remote device. By default the remote and local endpoints use the same data format. However users may want to conserve bandwidth by using complex shorts over the link, and using floats locally. Specify {"remote:format":"CS16"} to use complex 16-bit integers over the link, or specify {"remote:format":"CS8"} to use complex 8-bit integers over the link; and the remote stream driver will perform the conversion to/from floating point.

The remote scalar specifies the floating point scale factor used when the user specifies floats locally and integers over the link. By default the scale factor is 32768 to convert between 1.0 full-scale floats and 16-bit integers, or 128 to convert between 1.0 full-scale floats and 8-bit integers. For the Blade RF, which uses the lower 12 bits, specify {"remote:format":"CS16", "remote:scalar":2048}.

The remote MTU specifies the maximum datagram transfer size in bytes. By default the MTU is just under 1500 bytes (the default ethernet MTU). Users may increase the MTU to improve throughput. Not all hardware supports jumbo-frames. Check your ethernet configuration and hardware support before using this option.

On linux, use ifconfig to set the ethernet MTU:

sudo ifconfig eth0 mtu 4096

The remote window specifies the size of the kernel socket buffer in bytes. For applications that can tolerate large queues of samples, a large socket buffer (10s of megabytes) is recommended. The operating system may limit the upper bounds of the socket buffer size. The driver will print a warning if the buffer limit is exceeded.

On linux, use sysctrl to set the maximum socket buffer size:

#I like big buffers and I can not lie
#You other developers can't deny
#That when a socket walks in with an itty bitty SO_RCVBUF
#And a sysctl limit in your face
#You must run,
sudo sysctl -w net.core.rmem_max=104857600
sudo sysctl -w net.core.wmem_max=104857600

The remote priority specifies the scheduling priority of the server forwarding threads. Its recommended to use an elevated priority for the forwarding threads to reduce latency and to avoid potential hiccups like overflows and underflows. The priority is a floating point value between -1.0 (low), 0.0 (normal), and 1.0 (high). By default, the server will try to elevate the priority for the forwarder threads. Users may need to tweak their system configuration to allow elevated thread priority. The driver will print a warning if the thread priority setting is not possible.

To allow elevated priority on linux, edit /etc/security/limits.conf and add the following line for your username:

<username> hard rtprio 99

SoapyRemote is composed of two major pieces: The server, which is an executable that runs on the remote machine. And the client, which is just a regular SoapySDR plugin module that knows how to communicate with the server.

The server operates a simple RPC protocol over the reliable TCP socket layer. The client connects to the server to perform device discovery, creation, and configuration settings. Stream configuration and controls are also implemented through the RPC, however the streams themselves use a separate protocol for high bandwidth.

Streaming operates through a windowed-datagram protcol over the unreliable UDP socket layer. A stream receiver endpoint socket is responsible for buffering the incoming stream data, and sending out flow control messages to the sender endpoint. The sender endpoint waits on flow control messages and forwards the stream data to the receiver. The goal of the flow control is to never send more data into the link, than there is space within the socket buffers.