### Build and Install SoapySDR Source: https://context7.com/pothosware/soapysdr/llms.txt Steps to build and install SoapySDR from source on Ubuntu, including dependency installation and verification using command-line tools. ```bash # Ubuntu dependencies sudo apt-get install cmake g++ libpython3-dev python3-numpy swig # Clone and build git clone https://github.com/pothosware/SoapySDR.git cd SoapySDR mkdir build && cd build cmake .. make -j$(nproc) sudo make install sudo ldconfig # Debian/Ubuntu only # Verify installation SoapySDRUtil --info SoapySDRUtil --find # list detected devices SoapySDRUtil --make="driver=rtlsdr" # test instantiating a device # Set custom module search path if needed export SOAPY_SDR_PLUGIN_PATH=/opt/SoapyRemote/lib/SoapySDR/modules0.8 ``` -------------------------------- ### Install Man Pages Source: https://github.com/pothosware/soapysdr/blob/master/apps/CMakeLists.txt Installs the man page for the SoapySDRUtil executable to the appropriate directory. ```cmake install(FILES SoapySDRUtil.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) ``` -------------------------------- ### Setup and Activate I/O Stream Source: https://context7.com/pothosware/soapysdr/llms.txt Initialize an I/O stream for one or more channels with a specified sample format and activate data flow. Use `setupStream` for resource allocation and `activateStream` for enabling data transfer. Cleanup involves deactivating and closing the stream. ```cpp #include #include // SOAPY_SDR_CF32, SOAPY_SDR_CS16, etc. #include SoapySDR::Device *sdr = SoapySDR::Device::make("driver=rtlsdr"); sdr->setSampleRate(SOAPY_SDR_RX, 0, 2.4e6); sdr->setFrequency(SOAPY_SDR_RX, 0, 96.9e6); // 96.9 MHz FM station // Single-channel RX stream of complex float32 samples SoapySDR::Stream *rxStream = sdr->setupStream( SOAPY_SDR_RX, SOAPY_SDR_CF32, // "CF32" — complex float (8 bytes/sample) {0}, // channel list: channel 0 only {} // stream args: defaults ); // Multi-channel stream (if hardware supports it) SoapySDR::Stream *rxMC = sdr->setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, {0, 1}); // Activate: optionally set a hardware start timestamp // flags = SOAPY_SDR_HAS_TIME to honor timeNs sdr->activateStream(rxStream, 0, 0, 0); // start now, continuous // Query MTU for optimal buffer sizing size_t mtu = sdr->getStreamMTU(rxStream); printf("Stream MTU: %zu samples\n", mtu); // e.g. 1024 // --- Cleanup --- sdr->deactivateStream(rxStream, 0, 0); sdr->closeStream(rxStream); SoapySDR::Device::unmake(sdr); // Available format constants: // SOAPY_SDR_CF64 "CF64" complex double (16 bytes) // SOAPY_SDR_CF32 "CF32" complex float (8 bytes) // SOAPY_SDR_CS32 "CS32" complex int32 (8 bytes) // SOAPY_SDR_CS16 "CS16" complex int16 (4 bytes) // SOAPY_SDR_CS12 "CS12" complex int12 (3 bytes) // SOAPY_SDR_CS8 "CS8" complex int8 (2 bytes) // SOAPY_SDR_CS4 "CS4" complex int4 (1 byte) // SOAPY_SDR_F32 "F32" real float (4 bytes) // SOAPY_SDR_S16 "S16" real int16 (2 bytes) ``` -------------------------------- ### Stream Setup and Activation Source: https://context7.com/pothosware/soapysdr/llms.txt Initializes an I/O stream for one or more channels in a given sample format and activates data flow. `setupStream()` allocates DMA resources; `activateStream()` is a lightweight on-switch that can be called repeatedly. ```APIDOC ## Stream Setup and Activation — `setupStream()` / `activateStream()` Initializes an I/O stream for one or more channels in a given sample format and activates data flow. `setupStream()` allocates DMA resources; `activateStream()` is a lightweight on-switch that can be called repeatedly. The format string first character selects type (`C`=complex, `F`=float, `S`=signed int, `U`=unsigned int) followed by bits per component. ```cpp #include #include // SOAPY_SDR_CF32, SOAPY_SDR_CS16, etc. #include SoapySDR::Device *sdr = SoapySDR::Device::make("driver=rtlsdr"); sdr->setSampleRate(SOAPY_SDR_RX, 0, 2.4e6); sdr->setFrequency(SOAPY_SDR_RX, 0, 96.9e6); // 96.9 MHz FM station // Single-channel RX stream of complex float32 samples SoapySDR::Stream *rxStream = sdr->setupStream( SOAPY_SDR_RX, SOAPY_SDR_CF32, // "CF32" — complex float (8 bytes/sample) {0}, // channel list: channel 0 only {} // stream args: defaults ); // Multi-channel stream (if hardware supports it) SoapySDR::Stream *rxMC = sdr->setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, {0, 1}); // Activate: optionally set a hardware start timestamp // flags = SOAPY_SDR_HAS_TIME to honor timeNs sdr->activateStream(rxStream, 0, 0, 0); // start now, continuous // Query MTU for optimal buffer sizing size_t mtu = sdr->getStreamMTU(rxStream); printf("Stream MTU: %zu samples\n", mtu); // e.g. 1024 // --- Cleanup --- sdr->deactivateStream(rxStream, 0, 0); sdr->closeStream(rxStream); SoapySDR::Device::unmake(sdr); // Available format constants: // SOAPY_SDR_CF64 "CF64" complex double (16 bytes) // SOAPY_SDR_CF32 "CF32" complex float (8 bytes) // SOAPY_SDR_CS32 "CS32" complex int32 (8 bytes) // SOAPY_SDR_CS16 "CS16" complex int16 (4 bytes) // SOAPY_SDR_CS12 "CS12" complex int12 (3 bytes) // SOAPY_SDR_CS8 "CS8" complex int8 (2 bytes) // SOAPY_SDR_CS4 "CS4" complex int4 (1 byte) // SOAPY_SDR_F32 "F32" real float (4 bytes) // SOAPY_SDR_S16 "S16" real int16 (2 bytes) ``` ``` -------------------------------- ### Enumerate SDR Devices Source: https://context7.com/pothosware/soapysdr/llms.txt C++ example demonstrating how to enumerate all available SDR devices or filter them by driver. Requires SoapySDR headers. ```cpp #include #include int main() { // Enumerate all devices SoapySDR::KwargsList results = SoapySDR::Device::enumerate(); for (size_t i = 0; i < results.size(); i++) { std::cout << "Found device #" << i << ":\n"; for (auto &kv : results[i]) std::cout << " " << kv.first << " = " << kv.second << "\n"; } // Enumerate with a filter string SoapySDR::KwargsList rtlDevices = SoapySDR::Device::enumerate("driver=rtlsdr"); std::cout << "RTL-SDR devices: " << rtlDevices.size() << "\n"; // Python equivalent: // results = SoapySDR.Device.enumerate() // results = SoapySDR.Device.enumerate({"driver": "rtlsdr"}) // C equivalent: // size_t length; // SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length); // SoapySDRKwargsList_clear(results, length); return 0; } // Typical output: // Found device #0: // driver = rtlsdr // label = Generic RTL2832U OEM :: 00000001 // serial = 00000001 ``` -------------------------------- ### Configure and Install pkg-config File with CMake Source: https://github.com/pothosware/soapysdr/blob/master/lib/CMakeLists.txt Configures the SoapySDR pkg-config file from a template and installs it to the system's pkg-config directory, enabling other software to easily find and link against SoapySDR. ```cmake configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/SoapySDR.in.pc ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) ``` -------------------------------- ### Complete C Example for SDR Reception Source: https://context7.com/pothosware/soapysdr/llms.txt This C example demonstrates a full end-to-end receive operation using the pure C API of SoapySDR. It is suitable for integration into C programs or other languages with C Foreign Function Interface (FFI). Ensure SoapySDR is installed and linked during compilation. ```c /* compile: gcc -std=c99 rx.c -lSoapySDR -o rx */ #include #include #include #include #include #include int main(void) { size_t length; /* Enumerate */ SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length); for (size_t i = 0; i < length; i++) { printf("Device #%zu: ", i); for (size_t j = 0; j < results[i].size; j++) printf("%s=%s ", results[i].keys[j], results[i].vals[j]); printf("\n"); } SoapySDRKwargsList_clear(results, length); /* Open device */ SoapySDRKwargs args = {}; SoapySDRKwargs_set(&args, "driver", "rtlsdr"); SoapySDRDevice *sdr = SoapySDRDevice_make(&args); SoapySDRKwargs_clear(&args); if (!sdr) { fprintf(stderr, "make fail: %s\n", SoapySDRDevice_lastError()); return 1; } /* Configure */ if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 2.048e6) != 0) fprintf(stderr, "setSampleRate: %s\n", SoapySDRDevice_lastError()); if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 96.9e6, NULL) != 0) fprintf(stderr, "setFrequency: %s\n", SoapySDRDevice_lastError()); SoapySDRDevice_setGainMode(sdr, SOAPY_SDR_RX, 0, 0); /* AGC off */ SoapySDRDevice_setGain(sdr, SOAPY_SDR_RX, 0, 40.0); /* Stream */ SoapySDRStream *rxStream = SoapySDRDevice_setupStream( sdr, SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL); if (!rxStream) { fprintf(stderr, "setupStream: %s\n", SoapySDRDevice_lastError()); goto done; } SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0); complex float buff[1024]; for (int i = 0; i < 20; i++) { void *buffs[] = {buff}; int flags; long long timeNs; int ret = SoapySDRDevice_readStream(sdr, rxStream, buffs, 1024, &flags, &timeNs, 100000); if (ret < 0) fprintf(stderr, "readStream err: %s\n", SoapySDR_errToStr(ret)); else printf("rx: %d samples, flags=%d, time=%lld\n", ret, flags, timeNs); } SoapySDRDevice_deactivateStream(sdr, rxStream, 0, 0); SoapySDRDevice_closeStream(sdr, rxStream); done: SoapySDRDevice_unmake(sdr); return 0; } ``` -------------------------------- ### Complete Python Example for SDR Reception and Transmission Source: https://context7.com/pothosware/soapysdr/llms.txt This Python example demonstrates full receive and transmit functionality using the SoapySDR Python API with NumPy buffers. It includes device enumeration, capability querying, configuration, sensor reading, and streaming for both RX and TX. Note that TX streaming is commented out by default. ```python import SoapySDR from SoapySDR import SOAPY_SDR_RX, SOAPY_SDR_TX, SOAPY_SDR_CF32 import numpy as np # --- Enumerate --- for result in SoapySDR.Device.enumerate(): print("Found:", result) # --- Open device --- sdr = SoapySDR.Device(dict(driver="rtlsdr")) # --- Query capabilities --- print("RX antennas: ", sdr.listAntennas(SOAPY_SDR_RX, 0)) print("RX gains: ", sdr.listGains(SOAPY_SDR_RX, 0)) print("RX freq range:", sdr.getFrequencyRange(SOAPY_SDR_RX, 0)) print("RX rate range:", sdr.getSampleRateRange(SOAPY_SDR_RX, 0)) # --- Configure RX --- sdr.setSampleRate(SOAPY_SDR_RX, 0, 2.048e6) sdr.setFrequency(SOAPY_SDR_RX, 0, 96.9e6) sdr.setGainMode(SOAPY_SDR_RX, 0, False) sdr.setGain(SOAPY_SDR_RX, 0, 40.0) sdr.setBandwidth(SOAPY_SDR_RX, 0, 2.0e6) sdr.setAntenna(SOAPY_SDR_RX, 0, "RX") # --- Read sensors --- for key in sdr.listSensors(): print(f" sensor {key} = {sdr.readSensor(key)}") # --- RX streaming --- rxStream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32) sdr.activateStream(rxStream) buff = np.zeros(1024, dtype=np.complex64) for i in range(20): sr = sdr.readStream(rxStream, [buff], len(buff), timeoutUs=int(1e5)) if sr.ret < 0: print(f"Error: {sr.ret}") else: power_dB = 10 * np.log10(np.mean(np.abs(buff[:sr.ret])**2) + 1e-12) print(f"rx: {sr.ret} samples, flags={sr.flags}, time={sr.timeNs} ns, pwr={power_dB:.1f} dBFS") sdr.deactivateStream(rxStream) sdr.closeStream(rxStream) # --- TX streaming (if supported) --- # sdr.setSampleRate(SOAPY_SDR_TX, 0, 1e6) # sdr.setFrequency(SOAPY_SDR_TX, 0, 433.92e6) # txStream = sdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32) # sdr.activateStream(txStream) # tone = np.exp(1j * 2 * np.pi * 100e3 * np.arange(1024) / 1e6).astype(np.complex64) # sw = sdr.writeStream(txStream, [tone], len(tone)) # print(f"tx: {sw.ret} samples written") # sdr.deactivateStream(txStream) # sdr.closeStream(txStream) ``` -------------------------------- ### Construct and Identify SDR Devices Source: https://context7.com/pothosware/soapysdr/llms.txt C++ example for creating and destroying SoapySDR device handles using markup strings or Kwargs maps. Demonstrates retrieving hardware information. ```cpp #include #include int main() { // Make by markup string SoapySDR::Device *sdr = SoapySDR::Device::make("driver=rtlsdr"); if (!sdr) throw std::runtime_error("Device::make failed"); // Make by Kwargs map SoapySDR::Kwargs args; args["driver"] = "hackrf"; args["serial"] = "0000000000000000a74b63dc3"; SoapySDR::Device *hackrf = SoapySDR::Device::make(args); // Parallel construction of multiple devices std::vector argsList = {"driver=rtlsdr", "driver=hackrf"}; std::vector devices = SoapySDR::Device::make(argsList); // Identify the device std::cout << "Driver: " << sdr->getDriverKey() << "\n"; // e.g. "RTLSDR" std::cout << "Hardware: " << sdr->getHardwareKey() << "\n"; // e.g. "RTL2832U" for (auto &kv : sdr->getHardwareInfo()) std::cout << kv.first << ": " << kv.second << "\n"; SoapySDR::Device::unmake(sdr); SoapySDR::Device::unmake(hackrf); SoapySDR::Device::unmake(devices); // parallel unmake return 0; } ``` -------------------------------- ### Basic C++ API Example for SoapySDR Source: https://github.com/pothosware/soapysdr/wiki/Cpp_API_Example This snippet shows how to enumerate SoapySDR devices, create a device instance, query its capabilities (antennas, gains, frequency ranges), configure settings (sample rate, frequency), set up a stream for receiving complex float samples, read a small buffer of samples, and then properly shut down the stream and device. ```cpp #include //stdandard output #include #include #include #include #include // std::string #include // std::vector<...> #include // std::map< ... , ... > #include int main() { // 0. enumerate devices (list all devices' information) SoapySDR::KwargsList results = SoapySDR::Device::enumerate(); SoapySDR::Kwargs::iterator it; for( int i = 0; i < results.size(); ++i) { printf("Found device #%d: ", i); for( it = results[i].begin(); it != results[i].end(); ++it) { printf("%s = %s\n", it->first.c_str(), it->second.c_str()); } printf("\n"); } // 1. create device instance // 1.1 set arguments // args can be user defined or from the enumeration result // We use first results as args here: SoapySDR::Kwargs args = results[0]; // 1.2 make device SoapySDR::Device *sdr = SoapySDR::Device::make(args); if( sdr == NULL ) { fprintf(stderr, "SoapySDR::Device::make failed\n"); return EXIT_FAILURE; } // 2. query device info std::vector< std::string > str_list; //string list // 2.1 antennas str_list = sdr->listAntennas( SOAPY_SDR_RX, 0); printf("Rx antennas: "); for(int i = 0; i < str_list.size(); ++i) printf("%s,", str_list[i].c_str()); printf("\n"); // 2.2 gains str_list = sdr->listGains( SOAPY_SDR_RX, 0); printf("Rx Gains: "); for(int i = 0; i < str_list.size(); ++i) printf("%s, ", str_list[i].c_str()); printf("\n"); // 2.3. ranges(frequency ranges) SoapySDR::RangeList ranges = sdr->getFrequencyRange( SOAPY_SDR_RX, 0); printf("Rx freq ranges: "); for(int i = 0; i < ranges.size(); ++i) printf("[%g Hz -> %g Hz], ", ranges[i].minimum(), ranges[i].maximum()); printf("\n"); // 3. apply settings sdr->setSampleRate( SOAPY_SDR_RX, 0, 10e6); sdr->setFrequency( SOAPY_SDR_RX, 0, 433e6); // 4. setup a stream (complex floats) SoapySDR::Stream *rx_stream = sdr->setupStream( SOAPY_SDR_RX, SOAPY_SDR_CF32); if( rx_stream == NULL) { fprintf( stderr, "Failed\n"); SoapySDR::Device::unmake( sdr ); return EXIT_FAILURE; } sdr->activateStream( rx_stream, 0, 0, 0); // 5. create a re-usable buffer for rx samples std::complex buff[1024]; // 6. receive some samples for( int i = 0; i < 10; ++i) { void *buffs[] = {buff}; int flags; long long time_ns; int ret = sdr->readStream( rx_stream, buffs, 1024, flags, time_ns, 1e5); printf("ret = %d, flags = %d, time_ns = %lld\n", ret, flags, time_ns); } // 7. shutdown the stream sdr->deactivateStream( rx_stream, 0, 0); //stop streaming sdr->closeStream( rx_stream ); // 8. cleanup device handle SoapySDR::Device::unmake( sdr ); printf("Done\n"); return EXIT_SUCCESS; } ``` -------------------------------- ### Install SoapySDR Library Targets with CMake Source: https://github.com/pothosware/soapysdr/blob/master/lib/CMakeLists.txt Installs the SoapySDR library, including shared (.so), static (.lib), and runtime (.dll) files, to their designated installation directories. It also exports the target for use by other CMake projects. ```cmake install(TARGETS SoapySDR EXPORT SoapySDRExport LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # .so file ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # .lib file RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # .dll file ) #export target to SoapySDR project config install(EXPORT SoapySDRExport DESTINATION ${CMAKE_LIB_DEST}) ``` -------------------------------- ### Basic SoapySDR C API Example Source: https://github.com/pothosware/soapysdr/wiki/C_API_Example This snippet shows how to enumerate devices, create a device instance, query device information (antennas, gains, frequency ranges), apply settings (sample rate, frequency), set up and read from a stream, and finally clean up resources. Compile with: gcc -std=c99 example.c -lSoapySDR && ./a.out. ```c #include #include #include //printf #include //free #include int main(void) { size_t length; //enumerate devices SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length); for (size_t i = 0; i < length; i++) { printf("Found device #%d: ", (int)i); for (size_t j = 0; j < results[i].size; j++) { printf("%s=%s, ", results[i].keys[j], results[i].vals[j]); } printf("\n"); } SoapySDRKwargsList_clear(results, length); //create device instance //args can be user defined or from the enumeration result SoapySDRKwargs args = {}; SoapySDRKwargs_set(&args, "driver", "rtlsdr"); SoapySDRDevice *sdr = SoapySDRDevice_make(&args); SoapySDRKwargs_clear(&args); if (sdr == NULL) { printf("SoapySDRDevice_make fail: %s\n", SoapySDRDevice_lastError()); return EXIT_FAILURE; } //query device info char** names = SoapySDRDevice_listAntennas(sdr, SOAPY_SDR_RX, 0, &length); printf("Rx antennas: "); for (size_t i = 0; i < length; i++) printf("%s, ", names[i]); printf("\n"); SoapySDRStrings_clear(&names, length); names = SoapySDRDevice_listGains(sdr, SOAPY_SDR_RX, 0, &length); printf("Rx gains: "); for (size_t i = 0; i < length; i++) printf("%s, ", names[i]); printf("\n"); SoapySDRStrings_clear(&names, length); SoapySDRRange *ranges = SoapySDRDevice_getFrequencyRange(sdr, SOAPY_SDR_RX, 0, &length); printf("Rx freq ranges: "); for (size_t i = 0; i < length; i++) printf("[%g Hz -> %g Hz], ", ranges[i].minimum, ranges[i].maximum); printf("\n"); free(ranges); //apply settings if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 1e6) != 0) { printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); } if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 912.3e6, NULL) != 0) { printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); } //setup a stream (complex floats) SoapySDRStream *rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL); if (rxStream == NULL) { printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); SoapySDRDevice_unmake(sdr); return EXIT_FAILURE; } SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0); //start streaming //create a re-usable buffer for rx samples complex float buff[1024]; //receive some samples for (size_t i = 0; i < 10; i++) { void *buffs[] = {buff}; //array of buffers int flags; //flags set by receive operation long long timeNs; //timestamp for receive buffer int ret = SoapySDRDevice_readStream(sdr, rxStream, buffs, 1024, &flags, &timeNs, 100000); printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs); } //shutdown the stream SoapySDRDevice_deactivateStream(sdr, rxStream, 0, 0); //stop streaming SoapySDRDevice_closeStream(sdr, rxStream); //cleanup device handle SoapySDRDevice_unmake(sdr); printf("Done\n"); return EXIT_SUCCESS; } ``` -------------------------------- ### Build SoapySDRUtil Executable Source: https://github.com/pothosware/soapysdr/blob/master/apps/CMakeLists.txt Defines the SoapySDRUtil executable, linking it against the SoapySDR library and installing it. Includes conditional include directories for MSVC builds. ```cmake add_executable(SoapySDRUtil SoapySDRUtil.cpp SoapySDRProbe.cpp SoapyRateTest.cpp ) if (MSVC) target_include_directories(SoapySDRUtil PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/msvc) endif () target_link_libraries(SoapySDRUtil SoapySDR) install(TARGETS SoapySDRUtil DESTINATION ${CMAKE_INSTALL_BINDIR}) ``` -------------------------------- ### Implementing a Custom SoapySDR Device Plugin Source: https://context7.com/pothosware/soapysdr/llms.txt This C++ code defines a custom device plugin by subclassing `SoapySDR::Device`. It includes implementations for core functionalities like getting driver/hardware keys, channel counts, sample rates, frequencies, and stream setup/management. This serves as a template for creating new hardware support modules. ```cpp // MyDevice.cpp — compile as shared library, install to SoapySDR modules path #include #include #include #include class MyDevice : public SoapySDR::Device { int _fd; public: MyDevice(const SoapySDR::Kwargs &args) : _fd(-1) { auto it = args.find("path"); std::string devPath = (it != args.end()) ? it->second : "/dev/mydevice0"; SoapySDR::logf(SOAPY_SDR_INFO, "Opening %s", devPath.c_str()); // _fd = open(devPath.c_str(), O_RDWR); } ~MyDevice() { /* close(_fd); */ } std::string getDriverKey() const override { return "MyDevice"; } std::string getHardwareKey() const override { return "MyHW-v1"; } size_t getNumChannels(const int dir) const override { return (dir == SOAPY_SDR_RX) ? 1 : 1; } bool getFullDuplex(const int, const size_t) const override { return true; } void setSampleRate(const int, const size_t, const double rate) override { SoapySDR::logf(SOAPY_SDR_DEBUG, "setSampleRate(%.3f MHz)", rate/1e6); // write rate to hardware register ... } double getSampleRate(const int, const size_t) const override { return 2.0e6; } void setFrequency(const int, const size_t, const double freq, const SoapySDR::Kwargs &) override { SoapySDR::logf(SOAPY_SDR_DEBUG, "setFrequency(%.3f MHz)", freq/1e6); } double getFrequency(const int, const size_t) const override { return 100e6; } SoapySDR::Stream *setupStream(const int dir, const std::string &fmt, const std::vector &, const SoapySDR::Kwargs &) override { if (fmt != "CF32") throw std::runtime_error("Unsupported format: " + fmt); return (SoapySDR::Stream *)this; // opaque handle } void closeStream(SoapySDR::Stream *) override {} int activateStream(SoapySDR::Stream *, const int, const long long, const size_t) override { return 0; } int deactivateStream(SoapySDR::Stream *, const int, const long long) override { return 0; } int readStream(SoapySDR::Stream *, void *const *buffs, const size_t n, int &flags, long long &timeNs, const long) override { // fill buffs[0] with samples from hardware... flags = 0; timeNs = 0; return (int)n; } }; // Discovery function: returns list of available devices SoapySDR::KwargsList findMyDevice(const SoapySDR::Kwargs &hints) { SoapySDR::KwargsList results; // scan for devices; filter by hints if provided... SoapySDR::Kwargs found; found["path"] = "/dev/mydevice0"; found["driver"] = "mydevice"; found["label"] = "My SDR Device v1"; results.push_back(found); return results; } // Factory function: instantiate device from args SoapySDR::Device *makeMyDevice(const SoapySDR::Kwargs &args) { return new MyDevice(args); } // Register with SoapySDR — the static instance triggers registration at load time static SoapySDR::Registry registerMyDevice("mydevice", &findMyDevice, &makeMyDevice, SOAPY_SDR_ABI_VERSION); ``` -------------------------------- ### Define Function to Build Python Module Source: https://github.com/pothosware/soapysdr/blob/master/swig/python/CMakeLists.txt This function encapsulates the logic for building and installing the Python module for a given Python version. It configures SWIG, sets target properties, and handles installation paths. ```cmake function(BUILD_PYTHON_MODULE PYTHON_VERSION) configure_file( ${SOAPYSDR_PYTHON_DIR}/SoapySDR.in.i ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i @ONLY) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i PROPERTIES CPLUSPLUS ON) if(${CMAKE_VERSION} VERSION_LESS "3.8") SWIG_ADD_MODULE(SoapySDR${PYTHON_VERSION} python ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i) else() SWIG_ADD_LIBRARY(SoapySDR${PYTHON_VERSION} LANGUAGE python SOURCES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i) endif() set(python_includes ${SoapySDR_INCLUDE_DIRS}) set(python_libraries SoapySDR Python${PYTHON_VERSION}::Module) set_target_properties(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PROPERTIES OUTPUT_NAME _SoapySDR) if(${SWIG_VERSION} VERSION_GREATER "4.0.0") set_target_properties(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PROPERTIES SWIG_COMPILE_OPTIONS -doxygen) endif() if(MINGW) # https://stackoverflow.com/a/50792585 if(CMAKE_SIZEOF_VOID_P EQUAL 8) target_compile_definitions(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE -DMS_WIN64=1) else() target_compile_definitions(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE -DMS_WIN32=1) endif() # As of Python 3.8, DLL dependencies are no longer searched for in the PATH, so statically link against # the GCC runtime so we don't have to worry about that. list(APPEND python_libraries -static-libgcc -static-libstdc++) endif() target_include_directories(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE ${python_includes}) SWIG_LINK_LIBRARIES(SoapySDR${PYTHON_VERSION} ${python_libraries}) set(get_python_lib ${SOAPYSDR_PYTHON_DIR}/get_python_lib.py) if (${PYTHON_VERSION} EQUAL 2) set(get_python_lib ${SOAPYSDR_PYTHON_DIR}/get_python2_lib.py) endif() execute_process( COMMAND ${Python${PYTHON_VERSION}_EXECUTABLE} ${get_python_lib} ${CMAKE_INSTALL_PREFIX} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE PYTHON_INSTALL_DIR) install( TARGETS ${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} DESTINATION ${PYTHON_INSTALL_DIR} ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.py DESTINATION ${PYTHON_INSTALL_DIR} ) endfunction() ``` -------------------------------- ### SoapySDR Device Settings API Demo Source: https://context7.com/pothosware/soapysdr/llms.txt Demonstrates writing and reading arbitrary vendor-specific device or per-channel settings using string key-value pairs. Settings are described via ArgInfo metadata, allowing for auto-generated UIs. ```cpp #include void settingsDemo(SoapySDR::Device *sdr) { // Enumerate available device-level settings for (auto &info : sdr->getSettingInfo()) { printf(" setting '%s' (type=%d, default='%s'): %s\n", info.key.c_str(), (int)info.type, info.value.c_str(), info.description.c_str()); if (!info.options.empty()) { printf(" options:"); for (auto &o : info.options) printf(" %s", o.c_str()); printf("\n"); } } // Write and read back a device setting (string form) sdr->writeSetting("biastee", "true"); printf("biastee = %s\n", sdr->readSetting("biastee").c_str()); // Typed helpers (uses SettingToString / StringToSetting internally) sdr->writeSetting("biastee", true); bool biastee = sdr->readSetting("biastee"); sdr->writeSetting("if_gain", 20.0); // Per-channel setting sdr->writeSetting(SOAPY_SDR_RX, 0, "iq_correction", "1"); std::string val = sdr->readSetting(SOAPY_SDR_RX, 0, "iq_correction"); printf("RX ch0 iq_correction = %s\n", val.c_str()); // Python equivalent: // sdr.writeSetting("biastee", "true") // sdr.writeSetting(SOAPY_SDR_RX, 0, "iq_correction", "1") } ``` -------------------------------- ### Transmit Streaming with writeStream() Source: https://context7.com/pothosware/soapysdr/llms.txt Writes samples to an active TX stream from caller-provided buffers, providing natural back-pressure. Handles tone generation, stream setup, and status polling. ```cpp #include #include #include #include #include #include void transmitTone(SoapySDR::Device *sdr) { sdr->setSampleRate(SOAPY_SDR_TX, 0, 1e6); sdr->setFrequency(SOAPY_SDR_TX, 0, 433.92e6); sdr->setGain(SOAPY_SDR_TX, 0, 20.0); // 20 dB TX gain SoapySDR::Stream *txStream = sdr->setupStream(SOAPY_SDR_TX, "CF32", {0}); sdr->activateStream(txStream); const size_t N = 1024; std::vector> buf(N); // Generate 100 kHz tone const double freq = 100e3, rate = 1e6; for (size_t i = 0; i < N; i++) { double phase = 2.0 * M_PI * freq * i / rate; buf[i] = {(float)std::cos(phase), (float)std::sin(phase)}; } const void *buffs[] = {buf.data()}; int flags = 0; long long timeNs = 0; for (int i = 0; i < 1000; i++) { int ret = sdr->writeStream(txStream, buffs, N, flags, timeNs, 100000); if (ret < 0) { printf("writeStream error: %s\n", SoapySDR_errToStr(ret)); break; } } // Send finite burst with end-of-burst flag flags = SOAPY_SDR_END_BURST; sdr->writeStream(txStream, buffs, N, flags, 0, 100000); // Poll TX stream status for underflow/time errors size_t chanMask; long long statusTimeNs; int statusFlags; int status = sdr->readStreamStatus(txStream, chanMask, statusFlags, statusTimeNs, 100000); if (status == SOAPY_SDR_UNDERFLOW) printf("TX Underflow!\n"); sdr->deactivateStream(txStream); sdr->closeStream(txStream); } ``` -------------------------------- ### SoapySDR Time / Hardware Timestamp API Demo Source: https://context7.com/pothosware/soapysdr/llms.txt Demonstrates reading and writing the device's hardware clock for precise timestamped transmissions and synchronized multi-device operation. Includes listing time sources, setting hardware time, scheduling TX bursts, and converting between ticks and nanoseconds. ```cpp #include #include // ticksToTimeNs / timeNsToTicks void timestampDemo(SoapySDR::Device *sdr) { // List available time sources (e.g. "internal", "pps", "gpsdo") for (auto &src : sdr->listTimeSources()) printf(" time source: %s\n", src.c_str()); sdr->setTimeSource("gpsdo"); // Check and set hardware clock if (sdr->hasHardwareTime()) { sdr->setHardwareTime(0); // reset to zero long long t0 = sdr->getHardwareTime(); printf("Hardware time: %lld ns\n", t0); } // Schedule a TX burst to start at a specific hardware time long long futureNs = sdr->getHardwareTime() + 500000000LL; // 500 ms from now SoapySDR::Stream *txStream = sdr->setupStream(SOAPY_SDR_TX, "CF32"); sdr->activateStream(txStream, SOAPY_SDR_HAS_TIME, futureNs, 0); // Convert between ticks and nanoseconds double sampleRate = 10e6; long long ticks = SoapySDR::timeNsToTicks(futureNs, sampleRate); long long back = SoapySDR::ticksToTimeNs(ticks, sampleRate); printf("ticks=%lld roundtrip=%lld ns\n", ticks, back); sdr->deactivateStream(txStream); sdr->closeStream(txStream); } ``` -------------------------------- ### Querying API, ABI, and Library Version Information Source: https://context7.com/pothosware/soapysdr/llms.txt Check API version, ABI version, and library build information at runtime. Use the ABI version to ensure compatibility between plugins and the loaded SoapySDR library. Compile-time macros are also available. ```cpp #include #include #include void versionDemo() { // Runtime version strings printf("API version: %s\n", SoapySDR::getAPIVersion().c_str()); // e.g. "0.8.2" printf("ABI version: %s\n", SoapySDR::getABIVersion().c_str()); // e.g. "0.8-3" printf("Lib version: %s\n", SoapySDR::getLibVersion().c_str()); // e.g. "0.8.1-g1234abc" // Compile-time version macros printf("Build API: 0x%06X\n", SOAPY_SDR_API_VERSION); // 0x000802 → 0.8.2 printf("Build ABI: %s\n", SOAPY_SDR_ABI_VERSION); // "0.8-3" // Compatibility check (plugins must match ABI) if (SoapySDR::getABIVersion() != SOAPY_SDR_ABI_VERSION) fprintf(stderr, "WARNING: ABI mismatch! Plugin built against %s, library is %s\n", SOAPY_SDR_ABI_VERSION, SoapySDR::getABIVersion().c_str()); else printf("ABI check: OK\n"); } ```