SDRDevice API example

This page of the documentation shows the usage example using the new SDRDevice API. More examples written with this API can be found in the src/examples directory.

Example dualRXTX written with the new API

  1/**
  2    @file   dualRXTX.cpp
  3    @author Lime Microsystems (www.limemicro.com)
  4    @brief  minimal RX loopback to Tx example
  5 */
  6#include "limesuiteng/limesuiteng.hpp"
  7#include <iostream>
  8#include <chrono>
  9#include <string_view>
 10#include <cmath>
 11#include <signal.h>
 12#ifdef USE_GNU_PLOT
 13    #include "gnuPlotPipe.h"
 14#endif
 15
 16using namespace lime;
 17using namespace std::literals::string_view_literals;
 18
 19static const double frequencyLO = 1.5e9;
 20float sampleRate = 10e6;
 21static uint8_t chipIndex = 0; // device might have several RF chips
 22
 23bool stopProgram(false);
 24void intHandler(int dummy)
 25{
 26    std::cout << "Stoppping\n"sv;
 27    stopProgram = true;
 28}
 29
 30static LogLevel logVerbosity = LogLevel::Error;
 31static void LogCallback(LogLevel lvl, const std::string& msg)
 32{
 33    if (lvl > logVerbosity)
 34        return;
 35    std::cout << msg << std::endl;
 36}
 37
 38int main(int argc, char** argv)
 39{
 40    lime::registerLogHandler(LogCallback);
 41    auto handles = DeviceRegistry::enumerate();
 42    if (handles.size() == 0)
 43    {
 44        std::cout << "No devices found\n"sv;
 45        return -1;
 46    }
 47    std::cout << "Devices found :"sv << std::endl;
 48    for (size_t i = 0; i < handles.size(); i++)
 49        std::cout << i << ": "sv << handles[i].Serialize() << std::endl;
 50    std::cout << std::endl;
 51
 52    // Use first available device
 53    SDRDevice* device = DeviceRegistry::makeDevice(handles.at(0));
 54    if (!device)
 55    {
 56        std::cout << "Failed to connect to device"sv << std::endl;
 57        return -1;
 58    }
 59    device->SetMessageLogCallback(LogCallback);
 60    device->Init();
 61
 62    // RF parameters
 63    SDRConfig config;
 64    for (int c = 0; c < 2; ++c) // MIMO
 65    {
 66        config.channel[c].rx.enabled = true;
 67        config.channel[c].rx.centerFrequency = frequencyLO;
 68        config.channel[c].rx.sampleRate = sampleRate;
 69        config.channel[c].rx.oversample = 2;
 70        config.channel[c].rx.lpf = 0;
 71        config.channel[c].rx.path = 2; // TODO: replace with string names
 72        config.channel[c].rx.calibrate = false;
 73
 74        config.channel[c].tx.enabled = true;
 75        config.channel[c].tx.sampleRate = sampleRate;
 76        config.channel[c].tx.oversample = 2;
 77        config.channel[c].tx.path = 2; // TODO: replace with string names
 78        config.channel[c].tx.centerFrequency = frequencyLO;
 79        config.channel[c].tx.calibrate = false;
 80    }
 81
 82    // Samples data streaming configuration
 83    StreamConfig stream;
 84
 85    stream.channels[TRXDir::Rx] = { 0, 1 };
 86    stream.channels[TRXDir::Tx] = { 0, 1 };
 87
 88    stream.format = DataFormat::F32;
 89    stream.linkFormat = DataFormat::I16;
 90
 91    signal(SIGINT, intHandler);
 92
 93    const int samplesInBuffer = 256 * 4;
 94    complex32f_t** rxSamples = new complex32f_t*[2]; // allocate two channels for simplicity
 95    for (int i = 0; i < 2; ++i)
 96        rxSamples[i] = new complex32f_t[samplesInBuffer];
 97
 98#ifdef USE_GNU_PLOT
 99    GNUPlotPipe gp;
100    gp.write("set size square\n set xrange[-1:1]\n set yrange[-1:1]\n");
101#endif
102
103    std::cout << "Configuring device ...\n"sv;
104    try
105    {
106        auto t1 = std::chrono::high_resolution_clock::now();
107        device->Configure(config, chipIndex);
108        auto t2 = std::chrono::high_resolution_clock::now();
109        std::cout << "SDR configured in "sv << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << "ms\n"sv;
110
111        device->StreamSetup(stream, chipIndex);
112        device->StreamStart(chipIndex);
113
114    } catch (std::runtime_error& e)
115    {
116        std::cout << "Failed to configure settings: "sv << e.what() << std::endl;
117        return -1;
118    } catch (std::logic_error& e)
119    {
120        std::cout << "Failed to configure settings: "sv << e.what() << std::endl;
121        return -1;
122    }
123    std::cout << "Stream started ...\n"sv;
124
125    auto startTime = std::chrono::high_resolution_clock::now();
126    auto t1 = startTime;
127    auto t2 = t1;
128
129    int totalSamplesReceived = 0;
130    uint32_t totalSamplesSent = 0;
131    float maxSignalAmplitude = 0;
132
133    StreamMeta rxMeta;
134    while (std::chrono::high_resolution_clock::now() - startTime < std::chrono::seconds(10) && !stopProgram)
135    {
136        uint32_t samplesRead = device->StreamRx(chipIndex, rxSamples, samplesInBuffer, &rxMeta);
137        totalSamplesReceived += samplesRead;
138
139        // process samples
140        for (uint32_t n = 0; n < samplesRead; ++n)
141        {
142            float amplitude = pow(rxSamples[0][n].real(), 2) + pow(rxSamples[0][n].imag(), 2);
143            if (amplitude > maxSignalAmplitude)
144                maxSignalAmplitude = amplitude;
145        }
146
147        StreamMeta txMeta;
148        txMeta.timestamp = rxMeta.timestamp + samplesInBuffer * 64;
149        txMeta.waitForTimestamp = true;
150        txMeta.flushPartialPacket = false;
151        uint32_t samplesSent = device->StreamTx(chipIndex, rxSamples, samplesInBuffer, &txMeta);
152        if (samplesSent < 0)
153        {
154            std::cout << "Failure to send\n"sv;
155            break;
156        }
157        totalSamplesSent += samplesSent;
158
159        t2 = std::chrono::high_resolution_clock::now();
160        if (t2 - t1 > std::chrono::seconds(1))
161        {
162            t1 = t2;
163            std::cout << "Total samples received: "sv << totalSamplesReceived << "  signal amplitude: "sv
164                      << std::sqrt(maxSignalAmplitude) << "  total samples sent: "sv << totalSamplesSent << std::endl;
165
166#ifdef USE_GNU_PLOT
167            gp.write("plot '-' with points title 'ch 0'");
168            for (std::size_t c = 1; c < stream.channels.at(TRXDir::Rx).size(); ++c)
169                gp.writef(", '-' with points title 'ch %i'\n", c);
170            for (std::size_t c = 0; c < stream.channels.at(TRXDir::Rx).size(); ++c)
171            {
172                for (uint32_t n = 0; n < samplesInBuffer; ++n)
173                    gp.writef("%f %f\n", rxSamples[c][n].real(), rxSamples[c][n].imag());
174                gp.write("e\n");
175                gp.flush();
176            }
177#endif
178            maxSignalAmplitude = 0;
179        }
180    }
181    DeviceRegistry::freeDevice(device);
182
183    for (int i = 0; i < 2; ++i)
184        delete[] rxSamples[i];
185    delete[] rxSamples;
186    return 0;
187}