LMS API example

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

Example dualRXTX written with the legacy LimeSuite API

  1/**
  2    @file   dualRXTX.cpp
  3    @author Lime Microsystems (www.limemicro.com)
  4    @brief  Dual channel RX/TX example
  5 */
  6#include "lime/LimeSuite.h"
  7#include <iostream>
  8#include <chrono>
  9#ifdef USE_GNU_PLOT
 10    #include "gnuPlotPipe.h"
 11#endif
 12
 13using namespace std;
 14
 15//Device structure, should be initialize to NULL
 16lms_device_t* device = NULL;
 17
 18int error()
 19{
 20    cout << "Error; exiting!" << endl;
 21    if (device != NULL)
 22        LMS_Close(device);
 23    exit(-1);
 24}
 25
 26int main(int argc, char** argv)
 27{
 28    //Find devices
 29    int n;
 30    lms_info_str_t list[8]; //should be large enough to hold all detected devices
 31    if ((n = LMS_GetDeviceList(list)) < 0) //NULL can be passed to only get number of devices
 32        error();
 33
 34    cout << "Devices found: " << n << endl; //print number of devices
 35    if (n < 1)
 36        return -1;
 37
 38    //open the first device
 39    if (LMS_Open(&device, list[0], NULL))
 40        error();
 41
 42    //Initialize device with default configuration
 43    //Do not use if you want to keep existing configuration
 44    //Use LMS_LoadConfig(device, "/path/to/file.ini") to load config from INI
 45    if (LMS_Init(device) != 0)
 46        error();
 47
 48    //Get number of channels
 49    if ((n = LMS_GetNumChannels(device, LMS_CH_RX)) < 0)
 50        error();
 51    cout << "Number of RX channels: " << n << endl;
 52    if ((n = LMS_GetNumChannels(device, LMS_CH_TX)) < 0)
 53        error();
 54    cout << "Number of TX channels: " << n << endl;
 55
 56    //Enable RX channel
 57    //Channels are numbered starting at 0
 58    if (LMS_EnableChannel(device, LMS_CH_RX, 0, true) != 0)
 59        error();
 60    if (LMS_EnableChannel(device, LMS_CH_RX, 1, true) != 0)
 61        error();
 62    //Enable TX channels
 63    if (LMS_EnableChannel(device, LMS_CH_TX, 0, true) != 0)
 64        error();
 65    if (LMS_EnableChannel(device, LMS_CH_TX, 1, true) != 0)
 66        error();
 67
 68    //Set RX center frequency to 1 GHz
 69    if (LMS_SetLOFrequency(device, LMS_CH_RX, 0, 1e9) != 0)
 70        error();
 71    if (LMS_SetLOFrequency(device, LMS_CH_RX, 1, 1e9) != 0)
 72        error();
 73    //Set TX center frequency to 1.2 GHz
 74    //Automatically selects antenna port
 75    if (LMS_SetLOFrequency(device, LMS_CH_TX, 0, 1.2e9) != 0)
 76        error();
 77    if (LMS_SetLOFrequency(device, LMS_CH_TX, 1, 1.2e9) != 0)
 78        error();
 79
 80    //Set sample rate to 10 MHz, preferred oversampling in RF 4x
 81    //This set sampling rate for all channels
 82    if (LMS_SetSampleRate(device, 10e6, 4) != 0)
 83        error();
 84
 85    //Set RX gain
 86    if (LMS_SetNormalizedGain(device, LMS_CH_RX, 0, 0.7) != 0)
 87        error();
 88    if (LMS_SetNormalizedGain(device, LMS_CH_RX, 1, 0.7) != 0)
 89        error();
 90    //Set TX gain
 91    if (LMS_SetNormalizedGain(device, LMS_CH_TX, 0, 0.4) != 0)
 92        error();
 93    if (LMS_SetNormalizedGain(device, LMS_CH_TX, 1, 0.4) != 0)
 94        error();
 95
 96    //Enable test signals generation in RX channels
 97    //To receive data from RF, remove these lines or change signal to LMS_TESTSIG_NONE
 98    if (LMS_SetTestSignal(device, LMS_CH_RX, 0, LMS_TESTSIG_NCODIV4, 0, 0) != 0)
 99        error();
100    if (LMS_SetTestSignal(device, LMS_CH_RX, 1, LMS_TESTSIG_NCODIV8F, 0, 0) != 0)
101        error();
102
103    //Streaming Setup
104
105    const int chCount = 2; //number of RX/TX streams
106    lms_stream_t rx_streams[chCount];
107    lms_stream_t tx_streams[chCount];
108    //Initialize streams
109    //All streams setups should be done before starting streams. New streams cannot be set-up if at least stream is running.
110    for (int i = 0; i < chCount; ++i)
111    {
112        rx_streams[i].channel = i; //channel number
113        rx_streams[i].fifoSize = 1024 * 1024; //fifo size in samples
114        rx_streams[i].throughputVsLatency = 0.5; //some middle ground
115        rx_streams[i].isTx = false; //RX channel
116        rx_streams[i].dataFmt = lms_stream_t::LMS_FMT_I12; //12-bit integers
117        if (LMS_SetupStream(device, &rx_streams[i]) != 0)
118            error();
119        tx_streams[i].channel = i; //channel number
120        tx_streams[i].fifoSize = 1024 * 1024; //fifo size in samples
121        tx_streams[i].throughputVsLatency = 0.5; //some middle ground
122        tx_streams[i].isTx = true; //TX channel
123        tx_streams[i].dataFmt = lms_stream_t::LMS_FMT_I12; //12-bit integers
124        if (LMS_SetupStream(device, &tx_streams[i]) != 0)
125            error();
126    }
127
128    //Initialize data buffers
129    const int bufersize = 1024 * 8; //complex samples per buffer
130    int16_t* buffers[chCount];
131    for (int i = 0; i < chCount; ++i)
132    {
133        buffers[i] = new int16_t[bufersize * 2]; //buffer to hold complex values (2*samples))
134    }
135
136    //Start streaming
137    for (int i = 0; i < chCount; ++i)
138    {
139        LMS_StartStream(&rx_streams[i]);
140        LMS_StartStream(&tx_streams[i]);
141    }
142
143    //Streaming
144
145    lms_stream_meta_t rx_metadata; //Use metadata for additional control over sample receive function behavior
146    rx_metadata.flushPartialPacket = false; //currently has no effect in RX
147    rx_metadata.waitForTimestamp = false; //currently has no effect in RX
148
149    lms_stream_meta_t tx_metadata; //Use metadata for additional control over sample send function behavior
150    tx_metadata.flushPartialPacket = false; //do not force sending of incomplete packet
151    tx_metadata.waitForTimestamp = true; //Enable synchronization to HW timestamp
152
153#ifdef USE_GNU_PLOT
154    GNUPlotPipe gp;
155    gp.write("set size square\n set xrange[-2050:2050]\n set yrange[-2050:2050]\n");
156#endif
157    auto t1 = chrono::high_resolution_clock::now();
158    auto t2 = t1;
159
160    while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(10)) //run for 10 seconds
161    {
162        for (int i = 0; i < chCount; ++i)
163        {
164            int samplesRead;
165            //Receive samples
166            samplesRead = LMS_RecvStream(&rx_streams[i], buffers[i], bufersize, &rx_metadata, 1000);
167            //Send samples with 1024*256 sample delay from RX (waitForTimestamp is enabled)
168            tx_metadata.timestamp = rx_metadata.timestamp + 1024 * 256;
169            LMS_SendStream(&tx_streams[i], buffers[i], samplesRead, &tx_metadata, 1000);
170        }
171
172        //Print stats every 1s
173        if (chrono::high_resolution_clock::now() - t2 > chrono::seconds(1))
174        {
175            t2 = chrono::high_resolution_clock::now();
176#ifdef USE_GNU_PLOT
177            //Plot samples
178            gp.write("plot '-' with points title 'ch 0'");
179            for (int i = 1; i < chCount; ++i)
180                gp.write(", '-' with points title 'ch 1'\n");
181            for (int i = 0; i < chCount; ++i)
182            {
183                for (uint32_t j = 0; j < bufersize / 8; ++j)
184                    gp.writef("%i %i\n", buffers[i][2 * j], buffers[i][2 * j + 1]);
185                gp.write("e\n");
186                gp.flush();
187            }
188#endif
189            //Print stats
190            lms_stream_status_t status;
191            LMS_GetStreamStatus(rx_streams, &status); //Obtain RX stream stats
192            cout << "RX rate: " << status.linkRate / 1e6 << " MB/s\n"; //link data rate (both channels))
193            cout << "RX 0 FIFO: " << 100 * status.fifoFilledCount / status.fifoSize << "%" << endl; //percentage of RX 0 fifo filled
194
195            LMS_GetStreamStatus(tx_streams, &status); //Obtain TX stream stats
196            cout << "TX rate: " << status.linkRate / 1e6 << " MB/s\n"; //link data rate (both channels))
197            cout << "TX 0 FIFO: " << 100 * status.fifoFilledCount / status.fifoSize << "%" << endl; //percentage of TX 0 fifo filled
198        }
199    }
200
201    //Stop streaming
202    for (int i = 0; i < chCount; ++i)
203    {
204        LMS_StopStream(&rx_streams[i]); //stream is stopped but can be started again with LMS_StartStream()
205        LMS_StopStream(&tx_streams[i]);
206    }
207    for (int i = 0; i < chCount; ++i)
208    {
209        LMS_DestroyStream(device, &rx_streams[i]); //stream is deallocated and can no longer be used
210        LMS_DestroyStream(device, &tx_streams[i]);
211        delete[] buffers[i];
212    }
213
214    //Close device
215    LMS_Close(device);
216
217    return 0;
218}