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