Page cover

SoapySDR

Overview

SoapySDR, a C++ library designed for properly formatting and running a SDR. I personally have used it in my SIGINT project and it is a great way to seamlessly and easily format devices and get it ready for RF scanning.

Installation

In order to use SoapySDR you must download the zip file from the Pothosware website, due to their download files not being updated, I recommend downloading an older version such as the 2019 Pothosware version. However, you can do this through CMake and skip all the additional setup with ease.

If you are not using CMake to build this project you must setup the C++ and Linker directories in order for SoapySDR to work which goes as the following:

  • C++ Additional Include Directories: C:\Program Files\PothosSDR\include

  • Linker Additional Library Directories: C:\Program Files\PothosSDR\lib

  • Linker Additional Dependencies SoapySDR.lib

Once all of this is setup you can now use SoapySDR! Which also paves our way into some examples of specific SoapySDR functions and their tasks.

Usage

Now before we get into it, this does require a little bit of C++ knowledge, especially knowing what vectors, kwargs, strings and for loops are. If you do not know these, I recommend checking W3Schools introduction to C++ guide in getting familiar with C++

We will also be creating our own header file which consist of the necessary library imports as well as some C macros for easy debugging statements.

#pragma once
#ifndef UTILS_H
#define UTILS_H

#include <SoapySDR/Version.hpp>
#include <SoapySDR/Modules.hpp>
#include <SoapySDR/Registry.hpp>
#include <SoapySDR/Device.hpp>
#include <SoapySDR/ConverterRegistry.hpp>
#include <iostream>


#include <string>
#include <vector>

using namespace std;

#define okay(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__)
#define warn(msg, ...) printf("[-] " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) printf("[i] " msg "\n", ##__VA_ARGS__)

#endif

Now! For our very first task we will be checking if an SDR is connecting to our device and then printing out some basic metadata of the device.

#include "enumeration.h"
#include "UTILS.h"

std::vector<std::string> Formatting()
{
	/*---[Grab Metadata from available SDRs]---*/

		SoapySDR::KwargsList enumerate = SoapySDR::Device::enumerate();
		if (enumerate.empty()) {
			warn("No devices found! Please check connections...");
		}
		else {

			okay("Devices found! Creating formatted drivers....");
			vector<string> SDR_MakeDevices;
			printf("---/*Checking Device Compatability...*/---\n");
			for (auto SDR = enumerate.begin(); SDR != enumerate.end(); ++SDR) {

				string SDR_driver;
				string SDR_serial;
				string SDR_MakeDevice;
				try {

					SDR_serial = SDR->at("serial");
					SDR_driver = SDR->at("driver");
					SDR_MakeDevice = "driver=" + SDR_driver + ",serial=" + SDR_serial;
					SDR_MakeDevices.push_back(SDR_MakeDevice);
					printf("[*] Total formatted device strings: %zu\n", SDR_MakeDevices.size());
					string SDR_label = SDR->at("label");
					string SDR_part_id = SDR->at("part_id");
					string SDR_version = SDR->at("version");

					string SDR_complete = SDR_driver + " " + SDR_serial + " " + SDR_label + " " + SDR_part_id + " " + SDR_version;
					okay("Complete information for all devices: %s", SDR_complete.c_str());

				}
				catch (const std::out_of_range& e) {
					warn("Exception caught: %s", e.what());
					continue;
				}
			}
			return SDR_MakeDevices;
		}
}

Looking at the C++ code above we see a few things being created...

Firstly, we are creating a SoapySDR::Kwargslist named enumerate which is equal to the function SoapySDR::Device::enumerate(). This is a very straightforward function, once ran, it will first check to make sure an SDR if connecting using if (enumerate.empty()) , If it passes the first if statement, it will then move on to printing some basic metadata. This consists of the SDR: Serial number, Driver information, label, ID part, and version. This all will then get saved into an std::vector<string> called SDR_MakeDevices which will store the information needed to properly format a SDR (its serial and driver information). The rest of the information is then saved onto SDR_Complete which is then called on alongside SDR_MakeDevices.

Example Output:

[+] Complete information for all devices: hackrf 0000000000000000XXXXXXXXXXXXXXX HackRF One #0 XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX 2018.01.1
[+] SDR Device Creation: driver=hackrf,serial=0000000000000000XXXXXXXXXXXXX

With your output it will properly show your SDR's serial, Part ID and label

Continuing with this trend we also need a function to properly 'make' the device in order to fully get it ready for use in GUI or CLI applications. This however, isn't difficult, all we have to do is take the SDR_MakeDevices that we saved from our Formatting function and loop through it for every available SDR connected.

#include "UTILS.h"
#include "enumeration.h"

SoapySDR::Device* MakeDev()
{
	try {

		std::vector<std::string> MakeDev = Formatting();

		for (const auto& SDR_MakeDevice : MakeDev)
		{
				okay("SDR Device Creation: %s", SDR_MakeDevice.c_str());
				SoapySDR::Device* device = SoapySDR::Device::make(SDR_MakeDevice);
				if (!device)
				{
					warn("Could not create a valid SDR Device! %s", SDR_MakeDevice.c_str());
					continue;
				}
				return device;
		}
	}
	catch (std::exception& e)
	{
		warn("Exception caught: %s", e.what());
		return nullptr;
	}
}

If you want to just create a SDR device and only care about the necessary components, you can significantly simplify the process by just grabbing the driver and hardware from device

#include "enumeration.h"

int enumeration(SoapySDR::Device* device) {
	try {

		/*---[Create device for SDR probing]---*/

		info("Driver= %s", device->getDriverKey().c_str());
		info("Hardware= %s", device->getHardwareKey().c_str());
		for (const auto& it : device->getHardwareInfo()) {
			std::cout << " " << it.first << "=" << it.second << std::endl;
		}
	}
	catch (std::exception& e) {
		warn("Exception caught: %s", e.what());
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

You may also see the #include "enumeration.h" this is just a header that holds the function and any parameters in it, so that it's easy to call in Main.cpp.

And that's it! You just created your very first SDR probing device, with this you can easily start up and application whether it be CubicSDR, RTL-SDR, Airspy, etc. This greatly simplifies the process and ensures that your SDR is ready for data capturing!

(And if you're feeling lazy, the cpp files will be linked below...)

584B
Open
1KB
Open
511B
Open

If you're interested in the rest of this project, or want to further advance your skills with SoapySDR, be sure to check out my Github Repository focusing on Signal Intelligence!

Last updated