Skip to content
Nicholas Corgan edited this page Nov 11, 2022 · 7 revisions

.NET bindings for SoapySDR

The .NET bindings for SoapySDR give the user access to the full SoapySDR functionality in C#. There are some differences between the C++ API and the .NET API, primarily to better match C# coding conventions and take advantage of native .NET capabilities to provide convenient extensions to the API. These changes will be explained below, and full .NET API documentation is available (TODO: link when uploaded) here.

There is currently no planned Mono support, as CMake only natively supports C# on Windows with MSVC.

Dependencies

The following dependencies are needed to build SoapySDR's .NET bindings. Links to prebuilt installers within.

  • MSVC toolkit 1920+ / Visual Studio 16+
  • CMake (3.8)+: necessary for native C# support
  • SWIG: used to bridge C++ and C#

Changes for .NET API

Device class properties

Per C# API convention, trivial SoapySDR::Device getters and setters are exposed via properties.

Read-write properties are generally device-wide and independent of RF direction. For example:

  • C++: rate = sdr->getMasterClockRate() and sdr->setMasterClockRate(rate)
  • .NET: rate = sdr.MasterClockRate and sdr.MasterClockRate = rate

Device identification getters are now accessed by read-only properties. For example:

  • C++: key = sdr->getHardwareKey()
  • .NET: key = sdr.HardwareKey

New stream classes

In a significant departure from the C++ API, streams are exposed as classes with their own read/write functions, rather than as opaque handles passed into the Device class. Streaming functions can read from and write to a variety of containers, allowing the classes to be used with managed C# types or arbitrary unsafe pointers.

TX

  • T[], T[][]
  • System.ReadOnlyMemory<T>, System.ReadOnlyMemory<T>[]
  • System.ReadOnlySpan<T> (single-channel only)
  • IntPtr, IntPtr[]

RX

  • T[], T[][]
  • System.Memory<T>, System.Memory<T>[]
  • System.Span<T> (single-channel only)
  • IntPtr, IntPtr[]

Also, rather than returning multiple values via output parameters, streaming functions return these values via a single output class, whose fields correspond to the output values for the given function. See Pothosware.SoapySDR.StreamResult.

Other

  • SOAPY_SDR_* #defines have been changed to proper C# enums. For example, SOAPY_SDR_TX becomes Pothosware.SoapySDR.Direction.Tx.
  • Functions that accept SoapySDR::Kwargs as arguments on the C++ layer can accept either a string or any IDictionary<string, string> subclass.

Basic example

// Enumerate devices.
var results = Pothosware.SoapySDR.Device.Enumerate();
foreach(var result in results)
    System.Console.WriteLine(result);

// Create device instance.
// Args can be user-defined or from the enumeration result.
var args = "driver=rtlsdr";
var sdr = new Pothosware.SoapySDR.Device(args);

// Query device info.
System.Console.WriteLine("Antennas:");
foreach(var antenna in sdr.ListAntennas(Pothosware.SoapySDR.Direction.Rx, 0)))
    System.Console.WriteLine(" * " + antenna);

System.Console.WriteLine("Gains:");
foreach(var gain in sdr.ListGains(Pothosware.SoapySDR.Direction.Rx, 0)))
    System.Console.WriteLine(" * " + gain);

System.Console.WriteLine("Frequency ranges:");
foreach(var freqRange in sdr.GetFrequencyRange(Pothosware.SoapySDR.Direction.Rx, 0)))
    System.Console.WriteLine(" * " + freqRange);

// Apply settings.
sdr.SetSampleRate(Pothosware.SoapySDR.Direction.Rx, 0, 1e6);
sdr.SetFrequency(Pothosware.SoapySDR.Direction.Rx, 0, 912.3e6);

// Setup a stream (complex floats).
var rxStream = sdr.SetupRxStream<float>(new uint[]{0}, "");
rxStream.Activate(); // Start streaming

// Create a reusable array for RX samples.
var buff = new float[rxStream.MTU * 2];

// Receive some samples.
for(var i = 0; i < 10; ++i)
{
    Pothosware.SoapySDR.StreamResult streamResult;

    var errorCode = rxStream.Read<float>(ref buff, Pothosware.SoapySDR.StreamFlags.None, 0, 0, out streamResult);
    System.Console.WriteLine("Error code:     " + errorCode);
    System.Console.WriteLine("Receive flags:  " + streamResult.Flags);
    System.Console.WriteLine("Timestamp (ns): " + streamResult.TimeNs);
}

// Shut down the stream.
rxStream.Deactivate();
rxStream.Close();

More examples

Clone this wiki locally